mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 13:34:59 +00:00
Compare commits
211 Commits
0.12.0
...
presentati
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56be4d8921 | ||
|
|
4eb3148c26 | ||
|
|
e95d543ecd | ||
|
|
33af3d552b | ||
|
|
359a6042cd | ||
|
|
e27d2ec660 | ||
|
|
da56bfc01f | ||
|
|
6e2c7d2857 | ||
|
|
5481609554 | ||
|
|
a62f4df0b1 | ||
|
|
f893c1272c | ||
|
|
e701f5277e | ||
|
|
f85fd1f6a4 | ||
|
|
8f7ea420b3 | ||
|
|
d8c8dabb52 | ||
|
|
9092ecf331 | ||
|
|
2fd9fe96ad | ||
|
|
02f68b793c | ||
|
|
57b9133a0f | ||
|
|
815f5e09e8 | ||
|
|
5bdf01ee59 | ||
|
|
bd9417e74c | ||
|
|
694e869162 | ||
|
|
45845f8963 | ||
|
|
a8b6def76a | ||
|
|
a4ebd5fb3d | ||
|
|
3da3b212fa | ||
|
|
c2528cf93e | ||
|
|
550fecd4d3 | ||
|
|
50b01428b4 | ||
|
|
bb59f28b22 | ||
|
|
7064cda6de | ||
|
|
525c1873e8 | ||
|
|
3d91b4eb5e | ||
|
|
f20c03180e | ||
|
|
08fee76b4e | ||
|
|
0f511c4b2a | ||
|
|
42d9dfd117 | ||
|
|
3983db08ff | ||
|
|
72114bceea | ||
|
|
c303f96682 | ||
|
|
0e785968c4 | ||
|
|
15110e18e2 | ||
|
|
5465af041b | ||
|
|
310d56fc16 | ||
|
|
231258ef69 | ||
|
|
16b7e3ffc8 | ||
|
|
513e59f830 | ||
|
|
b10a1cf2bd | ||
|
|
1656edaa29 | ||
|
|
cff49aacba | ||
|
|
19c32aff6c | ||
|
|
db3ec8337f | ||
|
|
e7bfc40461 | ||
|
|
3d3ca254ba | ||
|
|
b45bc859a4 | ||
|
|
912d7a8775 | ||
|
|
16885da1b5 | ||
|
|
26714052eb | ||
|
|
3df763a783 | ||
|
|
925842bc4b | ||
|
|
cead62704e | ||
|
|
3f24a744c0 | ||
|
|
cce97548a2 | ||
|
|
9270d7cabf | ||
|
|
264aa6d366 | ||
|
|
69fc74e376 | ||
|
|
a361d41e68 | ||
|
|
38766dac99 | ||
|
|
c30bc65281 | ||
|
|
296ebd942a | ||
|
|
afa19f7ad8 | ||
|
|
a193b2d3b1 | ||
|
|
be4a65e572 | ||
|
|
6832918e71 | ||
|
|
fd9a3ffbcc | ||
|
|
41added690 | ||
|
|
18641d4f9b | ||
|
|
4d0c5099d4 | ||
|
|
9d9d491245 | ||
|
|
7b81d18071 | ||
|
|
7d0acbc988 | ||
|
|
313c044c41 | ||
|
|
f6f8adf97e | ||
|
|
bc97d325ca | ||
|
|
0f2d325f20 | ||
|
|
63d5503e12 | ||
|
|
e53f2cac4a | ||
|
|
3b73464233 | ||
|
|
575f10f766 | ||
|
|
8d3fc3533b | ||
|
|
60370b8539 | ||
|
|
f6db114865 | ||
|
|
1c6c344b6b | ||
|
|
d0302898e0 | ||
|
|
057ac9b001 | ||
|
|
8be931bbcb | ||
|
|
3197ef289c | ||
|
|
631578c175 | ||
|
|
f1809163c7 | ||
|
|
60e1fe86f2 | ||
|
|
59d7de5bfc | ||
|
|
6e95c1d84a | ||
|
|
ee64670755 | ||
|
|
3f7d0f5b68 | ||
|
|
e3514c5c4b | ||
|
|
cc3a9cff88 | ||
|
|
15e821aa39 | ||
|
|
8dd1dbab5f | ||
|
|
65ce91ddf6 | ||
|
|
bf55595d6f | ||
|
|
2aa123ccd7 | ||
|
|
0990b06cc9 | ||
|
|
e05f9843ba | ||
|
|
683d2714d0 | ||
|
|
b8ef1ecafc | ||
|
|
467fc2d03d | ||
|
|
58b4fe4f28 | ||
|
|
97d5e0aac4 | ||
|
|
356c977cff | ||
|
|
99d6062376 | ||
|
|
f8538403e4 | ||
|
|
ba12019bc7 | ||
|
|
726b9c80f6 | ||
|
|
2894711c51 | ||
|
|
85280f6f4f | ||
|
|
d7f4c0ee32 | ||
|
|
1263c0d976 | ||
|
|
cd3cbd2b32 | ||
|
|
b3a4fed8be | ||
|
|
d0b4af6666 | ||
|
|
81ab5c189d | ||
|
|
6ef3be4b5c | ||
|
|
9f90a1d651 | ||
|
|
ce9a3fd1ef | ||
|
|
7c6f05058e | ||
|
|
a8c3a7439e | ||
|
|
839b3ab0cf | ||
|
|
44d54db80e | ||
|
|
a67d7bc429 | ||
|
|
079a818c6c | ||
|
|
6be6ef0b5c | ||
|
|
8e51d9d646 | ||
|
|
ea206f4f02 | ||
|
|
f175a2a252 | ||
|
|
3f7e559b86 | ||
|
|
2959b4d701 | ||
|
|
031286c5eb | ||
|
|
e181fa8c4a | ||
|
|
7b035bec5d | ||
|
|
f39d2bf53a | ||
|
|
7c8e407182 | ||
|
|
a09136d46b | ||
|
|
5fe1363ee1 | ||
|
|
b41823fc10 | ||
|
|
0a64fe28b0 | ||
|
|
e320ccfa9a | ||
|
|
9628ff9456 | ||
|
|
d540f78cfc | ||
|
|
66420cd299 | ||
|
|
dd0594471f | ||
|
|
844ba228ee | ||
|
|
7efc701b32 | ||
|
|
d7e29f7c4d | ||
|
|
f26ba91386 | ||
|
|
c73ac2039c | ||
|
|
671f9cd0cb | ||
|
|
131b5b9714 | ||
|
|
74af0889b9 | ||
|
|
e5ee399045 | ||
| deeb7a0f64 | |||
|
|
5af3bab1dc | ||
|
|
28be84d315 | ||
|
|
a0528c737d | ||
|
|
b506e488e8 | ||
|
|
58eb0e08d6 | ||
|
|
562701894f | ||
|
|
54a562273b | ||
|
|
3f8c9c4cb0 | ||
|
|
3e7d28b043 | ||
|
|
40b10d4a26 | ||
|
|
f367630a2a | ||
|
|
b9e4f00862 | ||
|
|
d6e74d6163 | ||
|
|
4a4522b842 | ||
|
|
710ba4423d | ||
|
|
2a5494a804 | ||
|
|
568909800c | ||
|
|
7513a608b1 | ||
|
|
911e9878bd | ||
|
|
899d7d6e61 | ||
|
|
260c0ee776 | ||
|
|
d71520808d | ||
|
|
177fc2a12c | ||
|
|
5dafcb02d4 | ||
|
|
c4fde80c5e | ||
|
|
06e3486ec4 | ||
|
|
bd7c783aaf | ||
|
|
d732e3cfa4 | ||
|
|
c24cdc66ed | ||
|
|
efa6f7a82e | ||
| ddbbc3b847 | |||
|
|
7037161c07 | ||
|
|
b0b62fcf91 | ||
|
|
bd8ba7b854 | ||
|
|
3a52c68270 | ||
|
|
89fd778bd8 | ||
|
|
6e3e8343a8 | ||
|
|
9224237a99 | ||
|
|
8d16925662 | ||
|
|
ef0bf2758e |
15
.circleci/config.yml
Normal file
15
.circleci/config.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: microsoft/dotnet:2.0.5-sdk-2.1.4
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install unzip
|
||||
command: |
|
||||
apt-get update
|
||||
apt-get install -y unzip
|
||||
- run:
|
||||
name: Build
|
||||
command: ./build.sh
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -2,4 +2,4 @@
|
||||
* text=auto
|
||||
|
||||
# need original files to be windows
|
||||
test/TestArchives/Original/*.txt eol=crlf
|
||||
*.txt text eol=crlf
|
||||
31
.gitignore
vendored
31
.gitignore
vendored
@@ -1,14 +1,17 @@
|
||||
**/bin/*
|
||||
**/obj/*
|
||||
_ReSharper.SharpCompress/
|
||||
bin/
|
||||
*.suo
|
||||
*.user
|
||||
TestArchives/Scratch/
|
||||
TestArchives/Scratch2/
|
||||
TestResults/
|
||||
*.nupkg
|
||||
packages/*/
|
||||
project.lock.json
|
||||
test/TestArchives/Scratch
|
||||
.vs
|
||||
**/bin/*
|
||||
**/obj/*
|
||||
_ReSharper.SharpCompress/
|
||||
bin/
|
||||
*.suo
|
||||
*.user
|
||||
TestArchives/Scratch/
|
||||
TestArchives/Scratch2/
|
||||
TestResults/
|
||||
*.nupkg
|
||||
packages/*/
|
||||
project.lock.json
|
||||
tests/TestArchives/Scratch
|
||||
.vs
|
||||
tools
|
||||
.vscode
|
||||
.idea/
|
||||
|
||||
61
FORMATS.md
Normal file
61
FORMATS.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Formats
|
||||
|
||||
## Accessing Archives
|
||||
|
||||
- Archive classes allow random access to a seekable stream.
|
||||
- Reader classes allow forward-only reading on a stream.
|
||||
- Writer classes allow forward-only Writing on a stream.
|
||||
|
||||
## Supported Format Table
|
||||
|
||||
| Archive Format | Compression Format(s) | Compress/Decompress | Archive API | Reader API | Writer API |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Rar | Rar | Decompress (1) | RarArchive | RarReader | N/A |
|
||||
| Zip (2) | None, DEFLATE, Deflate64, BZip2, LZMA/LZMA2, PPMd | Both | ZipArchive | ZipReader | ZipWriter |
|
||||
| Tar | None | Both | TarArchive | TarReader | TarWriter (3) |
|
||||
| Tar.GZip | DEFLATE | Both | TarArchive | TarReader | TarWriter (3) |
|
||||
| Tar.BZip2 | BZip2 | Both | TarArchive | TarReader | TarWriter (3) |
|
||||
| Tar.LZip | LZMA | Both | TarArchive | TarReader | TarWriter (3) |
|
||||
| Tar.XZ | LZMA2 | Decompress | TarArchive | TarReader | TarWriter (3) |
|
||||
| GZip (single file) | DEFLATE | Both | GZipArchive | GZipReader | GZipWriter |
|
||||
| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | N/A | N/A |
|
||||
| LZip (single file) (5) | LZip (LZMA) | Both | LZipArchive | LZipReader | LZipWriter |
|
||||
|
||||
1. SOLID Rars are only supported in the RarReader API.
|
||||
2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported. Zip64 reading/writing is supported but only with seekable streams as the Zip spec doesn't support Zip64 data in post data descriptors. Deflate64 is only supported for reading.
|
||||
3. The Tar format requires a file size in the header. If no size is specified to the TarWriter and the stream is not seekable, then an exception will be thrown.
|
||||
4. The 7Zip format doesn't allow for reading as a forward-only stream so 7Zip is only supported through the Archive API
|
||||
5. LZip has no support for extra data like the file name or timestamp. There is a default filename used when looking at the entry Key on the archive.
|
||||
|
||||
## Compression Streams
|
||||
|
||||
For those who want to directly compress/decompress bits. The single file formats are represented here as well. However, BZip2, LZip and XZ have no metadata (GZip has a little) so using them without something like a Tar file makes little sense.
|
||||
|
||||
| Compressor | Compress/Decompress |
|
||||
| --- | --- |
|
||||
| BZip2Stream | Both |
|
||||
| GZipStream | Both |
|
||||
| DeflateStream | Both |
|
||||
| Deflate64Stream | Decompress |
|
||||
| LZMAStream | Both |
|
||||
| PPMdStream | Both |
|
||||
| ADCStream | Decompress |
|
||||
| LZipStream | Both |
|
||||
| XZStream | Decompress |
|
||||
|
||||
## Archive Formats vs Compression
|
||||
|
||||
Sometimes the terminology gets mixed.
|
||||
|
||||
### Compression
|
||||
|
||||
DEFLATE, LZMA are pure compression algorithms
|
||||
|
||||
### Formats
|
||||
|
||||
Formats like Zip, 7Zip, Rar are archive formats only. They use other compression methods (e.g. DEFLATE, LZMA, etc.) or propriatory (e.g RAR)
|
||||
|
||||
### Overlap
|
||||
|
||||
GZip, BZip2 and LZip are single file archival formats. The overlap in the API happens because Tar uses the single file formats as "compression" methods and the API tries to hide this a bit.
|
||||
|
||||
247
PITCHME.md
Normal file
247
PITCHME.md
Normal file
@@ -0,0 +1,247 @@
|
||||
|
||||
#### SharpCompress - Pure C# Archival and Compression
|
||||
|
||||
---
|
||||
|
||||
#### Overview
|
||||
|
||||
* History
|
||||
* Design
|
||||
* Archival Formats
|
||||
* Usages (Code!)
|
||||
|
||||
---
|
||||
|
||||
#### Why?
|
||||
|
||||
* Bored
|
||||
* Interested in Comics and wanted to make my own cross-platform viewer
|
||||
* Wrote a viewer in Sliverlight 2 using first versions of SharpCompress.
|
||||
* Used it on OS X
|
||||
|
||||
---
|
||||
|
||||
#### Initial Version
|
||||
|
||||
* Started as NUnrar on Codeplex
|
||||
* Used Visual Studio 2003 to convert JUnrar to C#
|
||||
* Cleaned up to have a nicer API
|
||||
|
||||
---
|
||||
|
||||
### More Formats
|
||||
|
||||
* Integrated DotNetZip
|
||||
* Created Unified API
|
||||
* Added Tar
|
||||
* Contributions: 7Zip, LZip, more!
|
||||
|
||||
---
|
||||
|
||||
# Design
|
||||
|
||||
---
|
||||
|
||||
### Unified APIs
|
||||
|
||||
* Random Access
|
||||
* Archive API
|
||||
* Forward-only
|
||||
* Reader API
|
||||
* Writer API
|
||||
* Neutral Factories
|
||||
|
||||
---
|
||||
|
||||
### Neural Factories
|
||||
|
||||
* Factories
|
||||
* `ArchiveFactory`
|
||||
* `ReaderFactory`
|
||||
* `WriterFactory`
|
||||
* Strategy
|
||||
* Look for Archive Signatures
|
||||
* "Rewind" if necessary with RewindableStream
|
||||
|
||||
---
|
||||
|
||||
### Random Access
|
||||
|
||||
* Random/Seekable access on a data stream (e.g. a File)
|
||||
* Strategy
|
||||
* Read Header, Skip Data
|
||||
* Dictionary
|
||||
|
||||
---
|
||||
|
||||
### Forward-only
|
||||
|
||||
* Everything is a stream of data
|
||||
* Support NetworkStreams
|
||||
* Very large files
|
||||
* `yield return` usage
|
||||
|
||||
---
|
||||
|
||||
# Formats
|
||||
|
||||
---
|
||||
|
||||
### Zip
|
||||
|
||||
* Header-Data Format
|
||||
* Optional data trailer (forward-only writing support)
|
||||
* Trailing dictionary of entries
|
||||
* pkware spec - APPNOTE.txt
|
||||
* Supports Reader API, Writer API and Archive API
|
||||
* Compression algorthims: just about everything
|
||||
* Deflate, BZ2, LZMA 1/2, PPMd
|
||||
|
||||
---
|
||||
|
||||
### Rar
|
||||
|
||||
* Header-Data Format
|
||||
* SOLID is a stream of compressed header-data pairs for small files
|
||||
* Multi-file archive
|
||||
* Unrar open-source, rar is closed-source
|
||||
* Supports Reader API and Archive API
|
||||
* Compression looks to be a modification of PPMd
|
||||
|
||||
---
|
||||
|
||||
### 7Zip
|
||||
|
||||
* Multi-data compressed Format
|
||||
* Headers are compressed
|
||||
* Multiple compressed "streams"
|
||||
* Readable Archive API support
|
||||
* Annoying
|
||||
* Known for LZMA
|
||||
|
||||
---
|
||||
|
||||
### Tar
|
||||
|
||||
* Header-Data Format
|
||||
* Supports Reader API, Writer API and Archive API
|
||||
* Uncompressed
|
||||
* Many additions to out-grow limitations
|
||||
* UStar
|
||||
* PAX
|
||||
|
||||
---
|
||||
|
||||
### GZip, BZip, LZip, Xz
|
||||
|
||||
* Header-Data Format of a single entry
|
||||
* Supports Reader API, Writer API and Archive API
|
||||
* Used with Tar
|
||||
* Compression
|
||||
* GZip - Deflate
|
||||
* BZip2 - BZip2
|
||||
* Xz - LZMA2
|
||||
* LZip - LZMA1 (improvement on Xz)
|
||||
|
||||
---
|
||||
|
||||
# Usages
|
||||
|
||||
---
|
||||
|
||||
### Reader
|
||||
|
||||
Writing entry to directory
|
||||
|
||||
```csharp
|
||||
using (Stream stream = new NetworkStream()) // pretend
|
||||
using (IReader reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
reader.WriteEntryToDirectory(test.SCRATCH_FILES_PATH, new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Reader
|
||||
|
||||
Writing entry to a stream
|
||||
|
||||
```csharp
|
||||
using (var reader = RarReader.Open("Rar.rar"))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
using (var entryStream = reader.OpenEntryStream())
|
||||
{
|
||||
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))
|
||||
{
|
||||
Directory.CreateDirectory(destdir);
|
||||
}
|
||||
string destinationFileName = Path.Combine(destdir, file);
|
||||
using (FileStream fs = File.OpenWrite(destinationFileName))
|
||||
{
|
||||
entryStream.TransferTo(fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Writer
|
||||
|
||||
Creating archive
|
||||
|
||||
```csharp
|
||||
using (Stream stream = File.OpenWrite("Test.tar.lz"))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.LZip))
|
||||
{
|
||||
writer.WriteAll("C:\", "*", SearchOption.AllDirectories);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Archive
|
||||
|
||||
---
|
||||
|
||||
### Projects
|
||||
|
||||
* Mono's Zip implementation
|
||||
* Nodatime
|
||||
* Octopus Deploy
|
||||
* Duplicati
|
||||
* Large ISO multi-file usage
|
||||
|
||||
---
|
||||
|
||||
### Open-source Notes
|
||||
|
||||
* Mostly solo effort
|
||||
* A few significant contributions
|
||||
* Russian friend did RarStream
|
||||
* Jon Skeet contributed LZip reading
|
||||
* Deflate64 recently added
|
||||
* Can always use help!
|
||||
* Multi-file zip support
|
||||
* Encryption in various formats (some support exists)
|
||||
* General clean up
|
||||
115
README.md
115
README.md
@@ -1,13 +1,29 @@
|
||||
# SharpCompress
|
||||
|
||||
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.
|
||||
SharpCompress is a compression library in pure C# for .NET 3.5, 4.5, .NET Standard 1.0, 1.3 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).
|
||||
|
||||
AppVeyor Build -
|
||||
[](https://ci.appveyor.com/project/adamhathcock/sharpcompress/branch/master)
|
||||
|
||||
Circle CI Build -
|
||||
[](https://circleci.com/gh/adamhathcock/sharpcompress)
|
||||
|
||||
## Need Help?
|
||||
Post Issues on Github!
|
||||
|
||||
Check the [Supported Formats](https://github.com/adamhathcock/sharpcompress/wiki/Supported-Formats) and [basic samples.](https://github.com/adamhathcock/sharpcompress/wiki/API-Examples)
|
||||
Check the [Supported Formats](FORMATS.md) and [Basic Usage.](USAGE.md)
|
||||
|
||||
## Recommended Formats
|
||||
|
||||
In general, I recommend GZip (Deflate)/BZip2 (BZip)/LZip (LZMA) as the simplicity of the formats lend to better long term archival as well as the streamability. Tar is often used in conjunction for multiple files in a single archive (e.g. `.tar.gz`)
|
||||
|
||||
Zip is okay, but it's a very hap-hazard format and the variation in headers and implementations makes it hard to get correct. Uses Deflate by default but supports a lot of compression methods.
|
||||
|
||||
RAR is not recommended as it's a propriatory format and the compression is closed source. Use Tar/LZip for LZMA
|
||||
|
||||
7Zip and XZ both are overly complicated. 7Zip does not support streamable formats. XZ has known holes explained here: (http://www.nongnu.org/lzip/xz_inadequate.html) Use Tar/LZip for LZMA compression instead.
|
||||
|
||||
## A Simple Request
|
||||
|
||||
@@ -23,18 +39,97 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
|
||||
|
||||
* RAR 5 support
|
||||
* 7Zip writing
|
||||
* Zip64
|
||||
* Zip64 (Need writing and extend Reading)
|
||||
* Multi-volume Zip support.
|
||||
|
||||
## In-Progress
|
||||
|
||||
* RAR5 support
|
||||
* DNX/NET Core support
|
||||
* xproj targeting
|
||||
|
||||
## Version Log
|
||||
|
||||
### Version 0.18
|
||||
|
||||
* [Now on Github releases](https://github.com/adamhathcock/sharpcompress/releases/tag/0.18)
|
||||
|
||||
### Version 0.17.1
|
||||
|
||||
* Fix - [Bug Fix for .NET Core on Windows](https://github.com/adamhathcock/sharpcompress/pull/257)
|
||||
|
||||
### Version 0.17.0
|
||||
|
||||
* New - Full LZip support! Can read and write LZip files and Tars inside LZip files. [Make LZip a first class citizen. #241](https://github.com/adamhathcock/sharpcompress/issues/241)
|
||||
* New - XZ read support! Can read XZ files and Tars inside XZ files. [XZ in SharpCompress #91](https://github.com/adamhathcock/sharpcompress/issues/94)
|
||||
* Fix - [Regression - zip file writing on seekable streams always assumed stream start was 0. Introduced with Zip64 writing.](https://github.com/adamhathcock/sharpcompress/issues/244)
|
||||
* Fix - [Zip files with post-data descriptors can be properly skipped via decompression](https://github.com/adamhathcock/sharpcompress/issues/162)
|
||||
|
||||
### Version 0.16.2
|
||||
|
||||
* Fix [.NET 3.5 should support files and cryptography (was a regression from 0.16.0)](https://github.com/adamhathcock/sharpcompress/pull/251)
|
||||
* Fix [Zip per entry compression customization wrote the wrong method into the zip archive](https://github.com/adamhathcock/sharpcompress/pull/249)
|
||||
|
||||
### Version 0.16.1
|
||||
|
||||
* Fix [Preserve compression method when getting a compressed stream](https://github.com/adamhathcock/sharpcompress/pull/235)
|
||||
* Fix [RAR entry key normalization fix](https://github.com/adamhathcock/sharpcompress/issues/201)
|
||||
|
||||
### Version 0.16.0
|
||||
|
||||
* Breaking - [Progress Event Tracking rethink](https://github.com/adamhathcock/sharpcompress/pull/226)
|
||||
* Update to VS2017 - [VS2017](https://github.com/adamhathcock/sharpcompress/pull/231) - Framework targets have been changed.
|
||||
* New - [Add Zip64 writing](https://github.com/adamhathcock/sharpcompress/pull/211)
|
||||
* [Fix invalid/mismatching Zip version flags.](https://github.com/adamhathcock/sharpcompress/issues/164) - This allows nuget/System.IO.Packaging to read zip files generated by SharpCompress
|
||||
* [Fix 7Zip directory hiding](https://github.com/adamhathcock/sharpcompress/pull/215/files)
|
||||
* [Verify RAR CRC headers](https://github.com/adamhathcock/sharpcompress/pull/220)
|
||||
|
||||
### Version 0.15.2
|
||||
|
||||
* [Fix invalid headers](https://github.com/adamhathcock/sharpcompress/pull/210) - fixes an issue creating large-ish zip archives that was introduced with zip64 reading.
|
||||
|
||||
### Version 0.15.1
|
||||
|
||||
* [Zip64 extending information and ZipReader](https://github.com/adamhathcock/sharpcompress/pull/206)
|
||||
|
||||
### Version 0.15.0
|
||||
|
||||
* [Add zip64 support for ZipArchive extraction](https://github.com/adamhathcock/sharpcompress/pull/205)
|
||||
|
||||
### Version 0.14.1
|
||||
|
||||
* [.NET Assemblies aren't strong named](https://github.com/adamhathcock/sharpcompress/issues/158)
|
||||
* [Pkware encryption for Zip files didn't allow for multiple reads of an entry](https://github.com/adamhathcock/sharpcompress/issues/197)
|
||||
* [GZip Entry couldn't be read multiple times](https://github.com/adamhathcock/sharpcompress/issues/198)
|
||||
|
||||
### Version 0.14.0
|
||||
|
||||
* [Support for LZip reading in for Tars](https://github.com/adamhathcock/sharpcompress/pull/191)
|
||||
|
||||
### Version 0.13.1
|
||||
|
||||
* [Fix null password on ReaderFactory. Fix null options on SevenZipArchive](https://github.com/adamhathcock/sharpcompress/pull/188)
|
||||
* [Make PpmdProperties lazy to avoid unnecessary allocations.](https://github.com/adamhathcock/sharpcompress/pull/185)
|
||||
|
||||
### Version 0.13.0
|
||||
|
||||
* Breaking change: Big refactor of Options on API.
|
||||
* 7Zip supports Deflate
|
||||
|
||||
### Version 0.12.4
|
||||
|
||||
* Forward only zip issue fix https://github.com/adamhathcock/sharpcompress/issues/160
|
||||
* Try to fix frameworks again by copying targets from JSON.NET
|
||||
|
||||
### Version 0.12.3
|
||||
|
||||
* 7Zip fixes https://github.com/adamhathcock/sharpcompress/issues/73
|
||||
* Maybe all profiles will work with project.json now
|
||||
|
||||
### Version 0.12.2
|
||||
|
||||
* Support Profile 259 again
|
||||
|
||||
### Version 0.12.1
|
||||
|
||||
* Support Silverlight 5
|
||||
|
||||
### Version 0.12.0
|
||||
|
||||
* .NET Core RTM!
|
||||
* Bug fix for Tar long paths
|
||||
|
||||
@@ -87,7 +182,7 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
|
||||
* Embedded some BouncyCastle crypto classes to allow RAR Decryption and Winzip AES Decryption in Portable and Windows Store DLLs
|
||||
* Built in Release (I think)
|
||||
|
||||
Some Help/Discussion: https://sharpcompress.codeplex.com/discussions
|
||||
XZ implementation based on: https://github.com/sambott/XZ.NET by @sambott
|
||||
|
||||
7Zip implementation based on: https://code.google.com/p/managed-lzma/
|
||||
|
||||
|
||||
@@ -1,44 +1,38 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F18F1765-4A02-42FD-9BEF-F0E2FCBD9D17}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress", "src\SharpCompress\SharpCompress.xproj", "{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C5BE746-03E5-4895-9988-0B57F162F86C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0F0901FF-E8D9-426A-B5A2-17C7F47C1529}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress.Test", "test\SharpCompress.Test\SharpCompress.Test.xproj", "{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {FD19DDD8-72B2-4024-8665-0D1F7A2AA998}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {3C5BE746-03E5-4895-9988-0B57F162F86C}
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5} = {0F0901FF-E8D9-426A-B5A2-17C7F47C1529}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26430.6
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F18F1765-4A02-42FD-9BEF-F0E2FCBD9D17}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C5BE746-03E5-4895-9988-0B57F162F86C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0F0901FF-E8D9-426A-B5A2-17C7F47C1529}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpCompress", "src\SharpCompress\SharpCompress.csproj", "{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpCompress.Test", "tests\SharpCompress.Test\SharpCompress.Test.csproj", "{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {3C5BE746-03E5-4895-9988-0B57F162F86C}
|
||||
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F} = {0F0901FF-E8D9-426A-B5A2-17C7F47C1529}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,6 +1,128 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=181069325DAB1C4287CD564D6CDDEDB3/AbsolutePath/@EntryValue">D:\Git\sharpcompress\SharpCompress\sharpcompress.DotSettings</s:String>
|
||||
<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=181069325DAB1C4287CD564D6CDDEDB3/RelativePath/@EntryValue">..\SharpCompress\sharpcompress.DotSettings</s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=181069325DAB1C4287CD564D6CDDEDB3/@KeyIndexDefined">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File181069325DAB1C4287CD564D6CDDEDB3/@KeyIndexDefined">True</s:Boolean>
|
||||
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File181069325DAB1C4287CD564D6CDDEDB3/RelativePriority/@EntryValue">1</s:Double></wpf:ResourceDictionary>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArgumentsStyleNamedExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fdowhile/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Ffixed/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Ffor/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fforeach/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fifelse/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Flock/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fusing/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fwhile/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MethodSupportsCancellation/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantExplicitParamsArrayCreation/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
|
||||
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Basic_0020Clean/@EntryIndexedValue"><?xml version="1.0" encoding="utf-16"?><Profile name="Basic Clean"><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="False" RemoveRedundantParentheses="False" AddMissingParentheses="False" ArrangeBraces="True" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CSReformatCode>True</CSReformatCode></Profile></s:String>
|
||||
|
||||
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue">Basic Clean</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/APPLY_ON_COMPLETION/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ARGUMENTS_NAMED/@EntryValue">Named</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_FIRST_ARG_BY_PAREN/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_LINQ_QUERY/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARGUMENT/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARRAY_AND_OBJECT_INITIALIZER/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXPRESSION/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_FOR_STMT/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_PARAMETER/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTIPLE_DECLARATION/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_CONSTRAINS/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_LIST/@EntryValue">True</s:Boolean>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AFTER_START_COMMENT/@EntryValue">0</s:Int64>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BEFORE_SINGLE_LINE_COMMENT/@EntryValue">1</s:Int64>
|
||||
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_ATTRIBUTE_STYLE/@EntryValue">SEPARATE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FIXED_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOR_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOREACH_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_IFELSE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_USING_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_ANONYMOUS_METHOD_BLOCK/@EntryValue">True</s:Boolean>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_CONSTRUCTOR_INITIALIZER_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSORHOLDER_ON_SINGLE_LINE/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_INITIALIZER_ON_SINGLE_LINE/@EntryValue">True</s:Boolean>
|
||||
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">True</s:Boolean>
|
||||
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_ARROW_OP/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_MULTIPLICATIVE_OP/@EntryValue">True</s:Boolean>
|
||||
|
||||
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_SIZEOF_PARENTHESES/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_TYPEOF_PARENTHESES/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/STICK_COMMENT/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARRAY_INITIALIZER_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_EXTENDS_LIST_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_PARAMETERS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseVarWhenEvident</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseVarWhenEvident</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseVarWhenEvident</s:String>
|
||||
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCLASS/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCONSTRUCTOR/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FFUNCTION/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FGLOBAL_005FVARIABLE/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLABEL/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FCONSTRUCTOR/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FVARIABLE/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FOBJECT_005FPROPERTY_005FOF_005FFUNCTION/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FPARAMETER/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FCLASS/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM_005FMEMBER/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FINTERFACE/@EntryIndexedValue"><Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FEXPORTED/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FLOCAL/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FMEMBER_005FACCESSOR/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FFIELD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FMETHOD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FMEMBER_005FACCESSOR/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FFIELD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FMETHOD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FMEMBER_005FACCESSOR/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FFIELD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FMETHOD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FTYPE_005FPARAMETER/@EntryIndexedValue"><Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FFIELD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FHTML_005FCONTROL/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FNAME/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FPREFIX/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=NAMESPACE_005FALIAS/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FFIELD/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FRESOURCE/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
||||
BIN
SharpCompress.snk
Normal file
BIN
SharpCompress.snk
Normal file
Binary file not shown.
131
USAGE.md
Normal file
131
USAGE.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# SharpCompress Usage
|
||||
|
||||
## Stream Rules
|
||||
When dealing with Streams, the rule should be that you don't close a stream you didn't create. This, in effect, should mean you should always put a Stream in a using block to dispose it.
|
||||
|
||||
However, the .NET Framework often has classes that will dispose streams by default to make things "easy" like the following:
|
||||
|
||||
```C#
|
||||
using (var reader = new StreamReader(File.Open("foo")))
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
In this example, reader should get disposed. However, stream rules should say the the `FileStream` created by `File.Open` should remain open. However, the .NET Framework closes it for you by default unless you override the constructor. In general, you should be writing Stream code like this:
|
||||
|
||||
```C#
|
||||
using (var fileStream = File.Open("foo"))
|
||||
using (var reader = new StreamReader(fileStream))
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
To deal with the "correct" rules as well as the expectations of users, I've decided on this:
|
||||
|
||||
* When writing, leave streams open.
|
||||
* When reading, close streams
|
||||
|
||||
To be explicit though, consider always using the overloads that use `ReaderOptions` or `WriterOptions` and explicitly set `LeaveStreamOpen` the way you want.
|
||||
|
||||
## Samples
|
||||
|
||||
Also, look over the tests for more thorough [examples](https://github.com/adamhathcock/sharpcompress/tree/master/test/SharpCompress.Test)
|
||||
|
||||
### Create Zip Archive from all files in a directory to a file
|
||||
|
||||
```C#
|
||||
using (var archive = ZipArchive.Create())
|
||||
{
|
||||
archive.AddAllFromDirectory("D:\\temp");
|
||||
archive.SaveTo("C:\\temp.zip", CompressionType.Deflate);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Create Zip Archive from all files in a directory and save in memory
|
||||
|
||||
```C#
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
using (var archive = ZipArchive.Create())
|
||||
{
|
||||
archive.AddAllFromDirectory("D:\\temp");
|
||||
archive.SaveTo(memoryStream, new WriterOptions(CompressionType.Deflate)
|
||||
{
|
||||
LeaveStreamOpen = true
|
||||
});
|
||||
}
|
||||
//reset memoryStream to be usable now
|
||||
memoryStream.Position = 0;
|
||||
```
|
||||
|
||||
### Extract all files from a Rar file to a directory using RarArchive
|
||||
|
||||
```C#
|
||||
using (var archive = RarArchive.Open("Test.rar"))
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory("D:\\temp", new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Use ReaderFactory to autodetect archive type and Open the entry stream
|
||||
|
||||
```C#
|
||||
using (Stream stream = File.OpenRead("Tar.tar.bz2"))
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Console.WriteLine(reader.Entry.Key);
|
||||
reader.WriteEntryToDirectory(@"C:\temp", new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Use ReaderFactory to autodetect archive type and Open the entry stream
|
||||
|
||||
```C#
|
||||
using (Stream stream = File.OpenRead("Tar.tar.bz2"))
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
using (var entryStream = reader.OpenEntryStream())
|
||||
{
|
||||
entryStream.CopyTo(...);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Use WriterFactory to write all files from a directory in a streaming manner.
|
||||
|
||||
```C#
|
||||
using (Stream stream = File.OpenWrite("C:\\temp.tgz"))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, new WriterOptions(CompressionType.GZip)
|
||||
{
|
||||
LeaveOpenStream = true
|
||||
}))
|
||||
{
|
||||
writer.WriteAll("D:\\temp", "*", SearchOption.AllDirectories);
|
||||
}
|
||||
```
|
||||
20
appveyor.yml
Normal file
20
appveyor.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
version: '{build}'
|
||||
image: Visual Studio 2017
|
||||
|
||||
pull_requests:
|
||||
do_not_increment_build_number: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
nuget:
|
||||
disable_publish_on_pr: true
|
||||
|
||||
build_script:
|
||||
- ps: .\build.ps1
|
||||
|
||||
test: off
|
||||
|
||||
artifacts:
|
||||
- path: src\SharpCompress\bin\Release\*.nupkg
|
||||
89
build.cake
Normal file
89
build.cake
Normal file
@@ -0,0 +1,89 @@
|
||||
var target = Argument("target", "Default");
|
||||
var tag = Argument("tag", "cake");
|
||||
|
||||
Task("Restore")
|
||||
.Does(() =>
|
||||
{
|
||||
DotNetCoreRestore(".");
|
||||
});
|
||||
|
||||
Task("Build")
|
||||
.IsDependentOn("Restore")
|
||||
.Does(() =>
|
||||
{
|
||||
if (IsRunningOnWindows())
|
||||
{
|
||||
MSBuild("./sharpcompress.sln", c =>
|
||||
{
|
||||
c.SetConfiguration("Release")
|
||||
.SetVerbosity(Verbosity.Minimal)
|
||||
.UseToolVersion(MSBuildToolVersion.VS2017);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var settings = new DotNetCoreBuildSettings
|
||||
{
|
||||
Framework = "netstandard1.0",
|
||||
Configuration = "Release",
|
||||
NoRestore = true
|
||||
};
|
||||
|
||||
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
|
||||
|
||||
settings.Framework = "netstandard1.3";
|
||||
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
|
||||
|
||||
settings.Framework = "netstandard2.0";
|
||||
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
|
||||
}
|
||||
});
|
||||
|
||||
Task("Test")
|
||||
.IsDependentOn("Build")
|
||||
.Does(() =>
|
||||
{
|
||||
var files = GetFiles("tests/**/*.csproj");
|
||||
foreach(var file in files)
|
||||
{
|
||||
var settings = new DotNetCoreTestSettings
|
||||
{
|
||||
Configuration = "Release",
|
||||
Framework = "netcoreapp2.0"
|
||||
};
|
||||
DotNetCoreTest(file.ToString(), settings);
|
||||
}
|
||||
});
|
||||
|
||||
Task("Pack")
|
||||
.IsDependentOn("Build")
|
||||
.Does(() =>
|
||||
{
|
||||
if (IsRunningOnWindows())
|
||||
{
|
||||
MSBuild("src/SharpCompress/SharpCompress.csproj", c => c
|
||||
.SetConfiguration("Release")
|
||||
.SetVerbosity(Verbosity.Minimal)
|
||||
.UseToolVersion(MSBuildToolVersion.VS2017)
|
||||
.WithProperty("NoBuild", "true")
|
||||
.WithTarget("Pack"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Information("Skipping Pack as this is not Windows");
|
||||
}
|
||||
});
|
||||
|
||||
Task("Default")
|
||||
.IsDependentOn("Restore")
|
||||
.IsDependentOn("Build")
|
||||
.IsDependentOn("Test")
|
||||
.IsDependentOn("Pack");
|
||||
|
||||
Task("RunTests")
|
||||
.IsDependentOn("Restore")
|
||||
.IsDependentOn("Build")
|
||||
.IsDependentOn("Test");
|
||||
|
||||
|
||||
RunTarget(target);
|
||||
228
build.ps1
Normal file
228
build.ps1
Normal file
@@ -0,0 +1,228 @@
|
||||
##########################################################################
|
||||
# This is the Cake bootstrapper script for PowerShell.
|
||||
# This file was downloaded from https://github.com/cake-build/resources
|
||||
# Feel free to change this file to fit your needs.
|
||||
##########################################################################
|
||||
|
||||
<#
|
||||
|
||||
.SYNOPSIS
|
||||
This is a Powershell script to bootstrap a Cake build.
|
||||
|
||||
.DESCRIPTION
|
||||
This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
|
||||
and execute your Cake build script with the parameters you provide.
|
||||
|
||||
.PARAMETER Script
|
||||
The build script to execute.
|
||||
.PARAMETER Target
|
||||
The build script target to run.
|
||||
.PARAMETER Configuration
|
||||
The build configuration to use.
|
||||
.PARAMETER Verbosity
|
||||
Specifies the amount of information to be displayed.
|
||||
.PARAMETER Experimental
|
||||
Tells Cake to use the latest Roslyn release.
|
||||
.PARAMETER WhatIf
|
||||
Performs a dry run of the build script.
|
||||
No tasks will be executed.
|
||||
.PARAMETER Mono
|
||||
Tells Cake to use the Mono scripting engine.
|
||||
.PARAMETER SkipToolPackageRestore
|
||||
Skips restoring of packages.
|
||||
.PARAMETER ScriptArgs
|
||||
Remaining arguments are added here.
|
||||
|
||||
.LINK
|
||||
http://cakebuild.net
|
||||
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[string]$Script = "build.cake",
|
||||
[string]$Target = "Default",
|
||||
[ValidateSet("Release", "Debug")]
|
||||
[string]$Configuration = "Release",
|
||||
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
|
||||
[string]$Verbosity = "Verbose",
|
||||
[switch]$Experimental,
|
||||
[Alias("DryRun","Noop")]
|
||||
[switch]$WhatIf,
|
||||
[switch]$Mono,
|
||||
[switch]$SkipToolPackageRestore,
|
||||
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
|
||||
[string[]]$ScriptArgs
|
||||
)
|
||||
|
||||
[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
|
||||
function MD5HashFile([string] $filePath)
|
||||
{
|
||||
if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
|
||||
{
|
||||
return $null
|
||||
}
|
||||
|
||||
[System.IO.Stream] $file = $null;
|
||||
[System.Security.Cryptography.MD5] $md5 = $null;
|
||||
try
|
||||
{
|
||||
$md5 = [System.Security.Cryptography.MD5]::Create()
|
||||
$file = [System.IO.File]::OpenRead($filePath)
|
||||
return [System.BitConverter]::ToString($md5.ComputeHash($file))
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ($file -ne $null)
|
||||
{
|
||||
$file.Dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Preparing to run build script..."
|
||||
|
||||
if(!$PSScriptRoot){
|
||||
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
|
||||
}
|
||||
|
||||
$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
|
||||
$ADDINS_DIR = Join-Path $TOOLS_DIR "addins"
|
||||
$MODULES_DIR = Join-Path $TOOLS_DIR "modules"
|
||||
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
|
||||
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
|
||||
$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
|
||||
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
|
||||
$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
|
||||
$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
|
||||
$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
|
||||
|
||||
# Should we use mono?
|
||||
$UseMono = "";
|
||||
if($Mono.IsPresent) {
|
||||
Write-Verbose -Message "Using the Mono based scripting engine."
|
||||
$UseMono = "-mono"
|
||||
}
|
||||
|
||||
# Should we use the new Roslyn?
|
||||
$UseExperimental = "";
|
||||
if($Experimental.IsPresent -and !($Mono.IsPresent)) {
|
||||
Write-Verbose -Message "Using experimental version of Roslyn."
|
||||
$UseExperimental = "-experimental"
|
||||
}
|
||||
|
||||
# Is this a dry run?
|
||||
$UseDryRun = "";
|
||||
if($WhatIf.IsPresent) {
|
||||
$UseDryRun = "-dryrun"
|
||||
}
|
||||
|
||||
# Make sure tools folder exists
|
||||
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
|
||||
Write-Verbose -Message "Creating tools directory..."
|
||||
New-Item -Path $TOOLS_DIR -Type directory | out-null
|
||||
}
|
||||
|
||||
# Make sure that packages.config exist.
|
||||
if (!(Test-Path $PACKAGES_CONFIG)) {
|
||||
Write-Verbose -Message "Downloading packages.config..."
|
||||
try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
|
||||
Throw "Could not download packages.config."
|
||||
}
|
||||
}
|
||||
|
||||
# Try find NuGet.exe in path if not exists
|
||||
if (!(Test-Path $NUGET_EXE)) {
|
||||
Write-Verbose -Message "Trying to find nuget.exe in PATH..."
|
||||
$existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
|
||||
$NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
|
||||
if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
|
||||
Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
|
||||
$NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
|
||||
}
|
||||
}
|
||||
|
||||
# Try download NuGet.exe if not exists
|
||||
if (!(Test-Path $NUGET_EXE)) {
|
||||
Write-Verbose -Message "Downloading NuGet.exe..."
|
||||
try {
|
||||
(New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE)
|
||||
} catch {
|
||||
Throw "Could not download NuGet.exe."
|
||||
}
|
||||
}
|
||||
|
||||
# Save nuget.exe path to environment to be available to child processed
|
||||
$ENV:NUGET_EXE = $NUGET_EXE
|
||||
|
||||
# Restore tools from NuGet?
|
||||
if(-Not $SkipToolPackageRestore.IsPresent) {
|
||||
Push-Location
|
||||
Set-Location $TOOLS_DIR
|
||||
|
||||
# Check for changes in packages.config and remove installed tools if true.
|
||||
[string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
|
||||
if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
|
||||
($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
|
||||
Write-Verbose -Message "Missing or changed package.config hash..."
|
||||
Remove-Item * -Recurse -Exclude packages.config,nuget.exe
|
||||
}
|
||||
|
||||
Write-Verbose -Message "Restoring tools from NuGet..."
|
||||
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Throw "An error occured while restoring NuGet tools."
|
||||
}
|
||||
else
|
||||
{
|
||||
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
|
||||
}
|
||||
Write-Verbose -Message ($NuGetOutput | out-string)
|
||||
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Restore addins from NuGet
|
||||
if (Test-Path $ADDINS_PACKAGES_CONFIG) {
|
||||
Push-Location
|
||||
Set-Location $ADDINS_DIR
|
||||
|
||||
Write-Verbose -Message "Restoring addins from NuGet..."
|
||||
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Throw "An error occured while restoring NuGet addins."
|
||||
}
|
||||
|
||||
Write-Verbose -Message ($NuGetOutput | out-string)
|
||||
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Restore modules from NuGet
|
||||
if (Test-Path $MODULES_PACKAGES_CONFIG) {
|
||||
Push-Location
|
||||
Set-Location $MODULES_DIR
|
||||
|
||||
Write-Verbose -Message "Restoring modules from NuGet..."
|
||||
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Throw "An error occured while restoring NuGet modules."
|
||||
}
|
||||
|
||||
Write-Verbose -Message ($NuGetOutput | out-string)
|
||||
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Make sure that Cake has been installed.
|
||||
if (!(Test-Path $CAKE_EXE)) {
|
||||
Throw "Could not find Cake.exe at $CAKE_EXE"
|
||||
}
|
||||
|
||||
# Start Cake
|
||||
Write-Host "Running build script..."
|
||||
Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs"
|
||||
exit $LASTEXITCODE
|
||||
42
build.sh
Executable file
42
build.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
##########################################################################
|
||||
# This is the Cake bootstrapper script for Linux and OS X.
|
||||
# This file was downloaded from https://github.com/cake-build/resources
|
||||
# Feel free to change this file to fit your needs.
|
||||
##########################################################################
|
||||
|
||||
# Define directories.
|
||||
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
TOOLS_DIR=$SCRIPT_DIR/tools
|
||||
CAKE_VERSION=0.26.0
|
||||
CAKE_DLL=$TOOLS_DIR/Cake.CoreCLR.$CAKE_VERSION/Cake.dll
|
||||
|
||||
# Make sure the tools folder exist.
|
||||
if [ ! -d "$TOOLS_DIR" ]; then
|
||||
mkdir "$TOOLS_DIR"
|
||||
fi
|
||||
|
||||
###########################################################################
|
||||
# INSTALL CAKE
|
||||
###########################################################################
|
||||
|
||||
if [ ! -f "$CAKE_DLL" ]; then
|
||||
curl -Lsfo Cake.CoreCLR.zip "https://www.nuget.org/api/v2/package/Cake.CoreCLR/$CAKE_VERSION" && unzip -q Cake.CoreCLR.zip -d "$TOOLS_DIR/Cake.CoreCLR.$CAKE_VERSION" && rm -f Cake.CoreCLR.zip
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "An error occured while installing Cake."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Make sure that Cake has been installed.
|
||||
if [ ! -f "$CAKE_DLL" ]; then
|
||||
echo "Could not find Cake.exe at '$CAKE_DLL'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
###########################################################################
|
||||
# RUN BUILD SCRIPT
|
||||
###########################################################################
|
||||
|
||||
# Start Cake
|
||||
exec dotnet "$CAKE_DLL" "$@"
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"projects": ["src","test"]
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archive.GZip
|
||||
{
|
||||
internal class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry
|
||||
{
|
||||
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.path = path;
|
||||
this.size = size;
|
||||
this.lastModified = lastModified;
|
||||
this.closeStream = closeStream;
|
||||
}
|
||||
|
||||
public override long Crc
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override string Key
|
||||
{
|
||||
get { return path; }
|
||||
}
|
||||
|
||||
public override long CompressedSize
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override long Size
|
||||
{
|
||||
get { return size; }
|
||||
}
|
||||
|
||||
public override DateTime? LastModifiedTime
|
||||
{
|
||||
get { return lastModified; }
|
||||
}
|
||||
|
||||
public override DateTime? CreatedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override DateTime? LastAccessedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override DateTime? ArchivedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override bool IsEncrypted
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool IsDirectory
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool IsSplit
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
internal override IEnumerable<FilePart> Parts
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
Stream IWritableArchiveEntry.Stream
|
||||
{
|
||||
get
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntryStream()
|
||||
{
|
||||
//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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archive.Tar
|
||||
{
|
||||
internal class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry
|
||||
{
|
||||
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.path = path;
|
||||
this.size = size;
|
||||
this.lastModified = lastModified;
|
||||
this.closeStream = closeStream;
|
||||
}
|
||||
|
||||
public override long Crc
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override string Key
|
||||
{
|
||||
get { return path; }
|
||||
}
|
||||
|
||||
public override long CompressedSize
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override long Size
|
||||
{
|
||||
get { return size; }
|
||||
}
|
||||
|
||||
public override DateTime? LastModifiedTime
|
||||
{
|
||||
get { return lastModified; }
|
||||
}
|
||||
|
||||
public override DateTime? CreatedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override DateTime? LastAccessedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override DateTime? ArchivedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override bool IsEncrypted
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool IsDirectory
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool IsSplit
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
internal override IEnumerable<FilePart> Parts
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
Stream IWritableArchiveEntry.Stream
|
||||
{
|
||||
get
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntryStream()
|
||||
{
|
||||
//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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archive.Zip
|
||||
{
|
||||
internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
|
||||
{
|
||||
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.path = path;
|
||||
this.size = size;
|
||||
this.lastModified = lastModified;
|
||||
this.closeStream = closeStream;
|
||||
}
|
||||
|
||||
public override long Crc
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override string Key
|
||||
{
|
||||
get { return path; }
|
||||
}
|
||||
|
||||
public override long CompressedSize
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override long Size
|
||||
{
|
||||
get { return size; }
|
||||
}
|
||||
|
||||
public override DateTime? LastModifiedTime
|
||||
{
|
||||
get { return lastModified; }
|
||||
}
|
||||
|
||||
public override DateTime? CreatedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override DateTime? LastAccessedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override DateTime? ArchivedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override bool IsEncrypted
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool IsDirectory
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool IsSplit
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
internal override IEnumerable<FilePart> Parts
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
Stream IWritableArchiveEntry.Stream
|
||||
{
|
||||
get
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntryStream()
|
||||
{
|
||||
//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 && !isDisposed)
|
||||
{
|
||||
stream.Dispose();
|
||||
isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Reader;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveExtractionListener
|
||||
where TEntry : IArchiveEntry
|
||||
@@ -20,31 +20,33 @@ namespace SharpCompress.Archive
|
||||
public event EventHandler<CompressedBytesReadEventArgs> CompressedBytesRead;
|
||||
public event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
|
||||
|
||||
protected string Password { get; private set; }
|
||||
protected ReaderOptions ReaderOptions { get; }
|
||||
|
||||
private bool disposed;
|
||||
|
||||
#if !NO_FILE
|
||||
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, Options options, string password)
|
||||
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, ReaderOptions readerOptions)
|
||||
{
|
||||
Type = type;
|
||||
Password = password;
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
throw new ArgumentException("File does not exist: " + fileInfo.FullName);
|
||||
}
|
||||
options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
|
||||
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(fileInfo, options));
|
||||
ReaderOptions = readerOptions;
|
||||
readerOptions.LeaveStreamOpen = false;
|
||||
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(fileInfo));
|
||||
lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
|
||||
}
|
||||
|
||||
|
||||
protected abstract IEnumerable<TVolume> LoadVolumes(FileInfo file, Options options);
|
||||
protected abstract IEnumerable<TVolume> LoadVolumes(FileInfo file);
|
||||
#endif
|
||||
|
||||
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, Options options, string password)
|
||||
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, ReaderOptions readerOptions)
|
||||
{
|
||||
Type = type;
|
||||
Password = password;
|
||||
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select(CheckStreams), options));
|
||||
ReaderOptions = readerOptions;
|
||||
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select(CheckStreams)));
|
||||
lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
|
||||
}
|
||||
|
||||
@@ -54,22 +56,17 @@ namespace SharpCompress.Archive
|
||||
lazyVolumes = new LazyReadOnlyCollection<TVolume>(Enumerable.Empty<TVolume>());
|
||||
lazyEntries = new LazyReadOnlyCollection<TEntry>(Enumerable.Empty<TEntry>());
|
||||
}
|
||||
public ArchiveType Type { get; private set; }
|
||||
|
||||
public ArchiveType Type { get; }
|
||||
|
||||
void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry)
|
||||
{
|
||||
if (EntryExtractionBegin != null)
|
||||
{
|
||||
EntryExtractionBegin(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
|
||||
}
|
||||
EntryExtractionBegin?.Invoke(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
|
||||
}
|
||||
|
||||
void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry)
|
||||
{
|
||||
if (EntryExtractionEnd != null)
|
||||
{
|
||||
EntryExtractionEnd(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
|
||||
}
|
||||
EntryExtractionEnd?.Invoke(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
|
||||
}
|
||||
|
||||
private static Stream CheckStreams(Stream stream)
|
||||
@@ -84,49 +81,29 @@ namespace SharpCompress.Archive
|
||||
/// <summary>
|
||||
/// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive.
|
||||
/// </summary>
|
||||
public virtual ICollection<TEntry> Entries
|
||||
{
|
||||
get { return lazyEntries; }
|
||||
}
|
||||
public virtual ICollection<TEntry> Entries { get { return lazyEntries; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive.
|
||||
/// </summary>
|
||||
public ICollection<TVolume> Volumes
|
||||
{
|
||||
get { return lazyVolumes; }
|
||||
}
|
||||
public ICollection<TVolume> Volumes { get { return lazyVolumes; } }
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the files compressed in the archive.
|
||||
/// </summary>
|
||||
public virtual long TotalSize
|
||||
{
|
||||
get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); }
|
||||
}
|
||||
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); }
|
||||
}
|
||||
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<TVolume> LoadVolumes(IEnumerable<Stream> streams);
|
||||
protected abstract IEnumerable<TEntry> LoadEntries(IEnumerable<TVolume> volumes);
|
||||
|
||||
IEnumerable<IArchiveEntry> IArchive.Entries
|
||||
{
|
||||
get { return Entries.Cast<IArchiveEntry>(); }
|
||||
}
|
||||
IEnumerable<IArchiveEntry> IArchive.Entries { get { return Entries.Cast<IArchiveEntry>(); } }
|
||||
|
||||
IEnumerable<IVolume> IArchive.Volumes
|
||||
{
|
||||
get { return lazyVolumes.Cast<IVolume>(); }
|
||||
}
|
||||
|
||||
private bool disposed;
|
||||
IEnumerable<IVolume> IArchive.Volumes { get { return lazyVolumes.Cast<IVolume>(); } }
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
@@ -146,27 +123,21 @@ namespace SharpCompress.Archive
|
||||
|
||||
void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
|
||||
{
|
||||
if (CompressedBytesRead != null)
|
||||
CompressedBytesRead?.Invoke(this, new CompressedBytesReadEventArgs
|
||||
{
|
||||
CompressedBytesRead(this, new CompressedBytesReadEventArgs()
|
||||
{
|
||||
CurrentFilePartCompressedBytesRead = currentPartCompressedBytes,
|
||||
CompressedBytesRead = compressedReadBytes
|
||||
});
|
||||
}
|
||||
CurrentFilePartCompressedBytesRead = currentPartCompressedBytes,
|
||||
CompressedBytesRead = compressedReadBytes
|
||||
});
|
||||
}
|
||||
|
||||
void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
|
||||
{
|
||||
if (FilePartExtractionBegin != null)
|
||||
FilePartExtractionBegin?.Invoke(this, new FilePartExtractionBeginEventArgs
|
||||
{
|
||||
FilePartExtractionBegin(this, new FilePartExtractionBeginEventArgs()
|
||||
{
|
||||
CompressedSize = compressedSize,
|
||||
Size = size,
|
||||
Name = name,
|
||||
});
|
||||
}
|
||||
CompressedSize = compressedSize,
|
||||
Size = size,
|
||||
Name = name
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -191,11 +162,7 @@ namespace SharpCompress.Archive
|
||||
/// <summary>
|
||||
/// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
|
||||
/// </summary>
|
||||
public virtual bool IsSolid
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public virtual bool IsSolid { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// The archive can find all the parts of the archive needed to fully extract the archive. This forces the parsing of the entire archive.
|
||||
@@ -3,8 +3,10 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>, IWritableArchive
|
||||
where TEntry : IArchiveEntry
|
||||
@@ -21,14 +23,14 @@ namespace SharpCompress.Archive
|
||||
{
|
||||
}
|
||||
|
||||
internal AbstractWritableArchive(ArchiveType type, Stream stream, Options options)
|
||||
: base(type, stream.AsEnumerable(), options, null)
|
||||
internal AbstractWritableArchive(ArchiveType type, Stream stream, ReaderOptions readerFactoryOptions)
|
||||
: base(type, stream.AsEnumerable(), readerFactoryOptions)
|
||||
{
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options)
|
||||
: base(type, fileInfo, options, null)
|
||||
internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, ReaderOptions readerFactoryOptions)
|
||||
: base(type, fileInfo, readerFactoryOptions)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@@ -53,10 +55,7 @@ namespace SharpCompress.Archive
|
||||
modifiedEntries.AddRange(OldEntries.Concat(newEntries));
|
||||
}
|
||||
|
||||
private IEnumerable<TEntry> OldEntries
|
||||
{
|
||||
get { return base.Entries.Where(x => !removedEntries.Contains(x)); }
|
||||
}
|
||||
private IEnumerable<TEntry> OldEntries { get { return base.Entries.Where(x => !removedEntries.Contains(x)); } }
|
||||
|
||||
public void RemoveEntry(TEntry entry)
|
||||
{
|
||||
@@ -66,25 +65,25 @@ namespace SharpCompress.Archive
|
||||
RebuildModifiedCollection();
|
||||
}
|
||||
}
|
||||
|
||||
void IWritableArchive.RemoveEntry(IArchiveEntry entry)
|
||||
{
|
||||
RemoveEntry((TEntry)entry);
|
||||
}
|
||||
|
||||
public TEntry AddEntry(string key, Stream source,
|
||||
long size = 0, DateTime? modified = null)
|
||||
long size = 0, DateTime? modified = null)
|
||||
{
|
||||
return AddEntry(key, source, false, size, modified);
|
||||
}
|
||||
|
||||
|
||||
IArchiveEntry IWritableArchive.AddEntry(string key, Stream source, bool closeStream, long size, DateTime? modified)
|
||||
{
|
||||
return AddEntry(key, source, closeStream, size, modified);
|
||||
}
|
||||
|
||||
public TEntry AddEntry(string key, Stream source, bool closeStream,
|
||||
long size = 0, DateTime? modified = null)
|
||||
long size = 0, DateTime? modified = null)
|
||||
{
|
||||
if (key.StartsWith("/")
|
||||
|| key.StartsWith("\\"))
|
||||
@@ -105,7 +104,7 @@ namespace SharpCompress.Archive
|
||||
{
|
||||
foreach (var path in Entries.Select(x => x.Key))
|
||||
{
|
||||
var p = path.Replace('/','\\');
|
||||
var p = path.Replace('/', '\\');
|
||||
if (p.StartsWith("\\"))
|
||||
{
|
||||
p = p.Substring(1);
|
||||
@@ -115,15 +114,15 @@ namespace SharpCompress.Archive
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SaveTo(Stream stream, CompressionInfo compressionType)
|
||||
public void SaveTo(Stream stream, WriterOptions options)
|
||||
{
|
||||
//reset streams of new entries
|
||||
newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
|
||||
SaveTo(stream, compressionType, OldEntries, newEntries);
|
||||
SaveTo(stream, options, OldEntries, newEntries);
|
||||
}
|
||||
|
||||
protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified,
|
||||
bool closeStream)
|
||||
bool closeStream)
|
||||
{
|
||||
if (!source.CanRead || !source.CanSeek)
|
||||
{
|
||||
@@ -133,10 +132,9 @@ namespace SharpCompress.Archive
|
||||
}
|
||||
|
||||
protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified,
|
||||
bool closeStream);
|
||||
bool closeStream);
|
||||
|
||||
protected abstract void SaveTo(Stream stream, CompressionInfo compressionType,
|
||||
IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
|
||||
protected abstract void SaveTo(Stream stream, WriterOptions options, IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
@@ -1,13 +1,15 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Archive.GZip;
|
||||
using SharpCompress.Archive.Rar;
|
||||
using SharpCompress.Archive.SevenZip;
|
||||
using SharpCompress.Archive.Tar;
|
||||
using SharpCompress.Archive.Zip;
|
||||
using SharpCompress.Archives.GZip;
|
||||
using SharpCompress.Archives.Rar;
|
||||
using SharpCompress.Archives.SevenZip;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Archives.Zip;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public class ArchiveFactory
|
||||
{
|
||||
@@ -15,46 +17,46 @@ namespace SharpCompress.Archive
|
||||
/// Opens an Archive for random access
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <returns></returns>
|
||||
public static IArchive Open(Stream stream, Options options = Options.KeepStreamsOpen)
|
||||
public static IArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
if (!stream.CanRead || !stream.CanSeek)
|
||||
{
|
||||
throw new ArgumentException("Stream should be readable and seekable");
|
||||
}
|
||||
|
||||
readerOptions = readerOptions ?? new ReaderOptions();
|
||||
if (ZipArchive.IsZipFile(stream, null))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return ZipArchive.Open(stream, options, null);
|
||||
return ZipArchive.Open(stream, readerOptions);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (SevenZipArchive.IsSevenZipFile(stream))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return SevenZipArchive.Open(stream, options);
|
||||
return SevenZipArchive.Open(stream, readerOptions);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (GZipArchive.IsGZipFile(stream))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return GZipArchive.Open(stream, options);
|
||||
return GZipArchive.Open(stream, readerOptions);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (RarArchive.IsRarFile(stream, options))
|
||||
if (RarArchive.IsRarFile(stream, readerOptions))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return RarArchive.Open(stream, options);
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return RarArchive.Open(stream, readerOptions);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (TarArchive.IsTarFile(stream))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return TarArchive.Open(stream, options);
|
||||
return TarArchive.Open(stream, readerOptions);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
|
||||
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip, LZip");
|
||||
}
|
||||
|
||||
public static IWritableArchive Create(ArchiveType type)
|
||||
@@ -62,52 +64,35 @@ namespace SharpCompress.Archive
|
||||
switch (type)
|
||||
{
|
||||
case ArchiveType.Zip:
|
||||
{
|
||||
return ZipArchive.Create();
|
||||
}
|
||||
{
|
||||
return ZipArchive.Create();
|
||||
}
|
||||
case ArchiveType.Tar:
|
||||
{
|
||||
return TarArchive.Create();
|
||||
}
|
||||
{
|
||||
return TarArchive.Create();
|
||||
}
|
||||
case ArchiveType.GZip:
|
||||
{
|
||||
return GZipArchive.Create();
|
||||
}
|
||||
{
|
||||
return GZipArchive.Create();
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException("Cannot create Archives of type: " + type);
|
||||
}
|
||||
{
|
||||
throw new NotSupportedException("Cannot create Archives of type: " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
public static IArchive 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 IArchive 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 IArchive Open(string filePath, Options options)
|
||||
public static IArchive Open(string filePath, ReaderOptions options = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
return Open(new FileInfo(filePath), options);
|
||||
return Open(new FileInfo(filePath), options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -115,15 +100,16 @@ namespace SharpCompress.Archive
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
public static IArchive Open(FileInfo fileInfo, Options options)
|
||||
public static IArchive Open(FileInfo fileInfo, ReaderOptions options = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
options = options ?? new ReaderOptions();
|
||||
using (var stream = fileInfo.OpenRead())
|
||||
{
|
||||
if (ZipArchive.IsZipFile(stream, null))
|
||||
{
|
||||
stream.Dispose();
|
||||
return ZipArchive.Open(fileInfo, options, null);
|
||||
return ZipArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (SevenZipArchive.IsSevenZipFile(stream))
|
||||
@@ -157,7 +143,7 @@ namespace SharpCompress.Archive
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public static void WriteToDirectory(string sourceArchive, string destinationDirectory,
|
||||
ExtractOptions options = ExtractOptions.Overwrite)
|
||||
ExtractionOptions options = null)
|
||||
{
|
||||
using (IArchive archive = Open(sourceArchive))
|
||||
{
|
||||
@@ -4,53 +4,37 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.GZip;
|
||||
using SharpCompress.Reader;
|
||||
using SharpCompress.Reader.GZip;
|
||||
using SharpCompress.Writer.GZip;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.GZip;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.GZip;
|
||||
|
||||
namespace SharpCompress.Archive.GZip
|
||||
namespace SharpCompress.Archives.GZip
|
||||
{
|
||||
public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
|
||||
{
|
||||
#if !NO_FILE
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
public static GZipArchive 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 GZipArchive 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 GZipArchive Open(string filePath, Options options)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static GZipArchive Open(string filePath, ReaderOptions readerOptions = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
return Open(new FileInfo(filePath), options);
|
||||
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
public static GZipArchive Open(FileInfo fileInfo, Options options)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static GZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
return new GZipArchive(fileInfo, options);
|
||||
return new GZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -58,21 +42,11 @@ namespace SharpCompress.Archive.GZip
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
public static GZipArchive Open(Stream stream)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static GZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return Open(stream, Options.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
public static GZipArchive Open(Stream stream, Options options)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return new GZipArchive(stream, options);
|
||||
return new GZipArchive(stream, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
public static GZipArchive Create()
|
||||
@@ -81,19 +55,20 @@ namespace SharpCompress.Archive.GZip
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
internal GZipArchive(FileInfo fileInfo, Options options)
|
||||
internal GZipArchive(FileInfo fileInfo, ReaderOptions options)
|
||||
: base(ArchiveType.GZip, fileInfo, options)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<GZipVolume> LoadVolumes(FileInfo file, Options options)
|
||||
protected override IEnumerable<GZipVolume> LoadVolumes(FileInfo file)
|
||||
{
|
||||
return new GZipVolume(file, options).AsEnumerable();
|
||||
return new GZipVolume(file, ReaderOptions).AsEnumerable();
|
||||
}
|
||||
|
||||
public static bool IsGZipFile(string filePath)
|
||||
@@ -122,7 +97,7 @@ namespace SharpCompress.Archive.GZip
|
||||
{
|
||||
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
SaveTo(stream);
|
||||
SaveTo(stream, new WriterOptions(CompressionType.GZip));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -131,17 +106,17 @@ namespace SharpCompress.Archive.GZip
|
||||
{
|
||||
// read the header on the first read
|
||||
byte[] header = new byte[10];
|
||||
int n = stream.Read(header, 0, header.Length);
|
||||
|
||||
// workitem 8501: handle edge case (decompress empty stream)
|
||||
if (n == 0)
|
||||
return false;
|
||||
|
||||
if (n != 10)
|
||||
if (!stream.ReadFully(header))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -151,7 +126,7 @@ namespace SharpCompress.Archive.GZip
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
internal GZipArchive(Stream stream, Options options)
|
||||
internal GZipArchive(Stream stream, ReaderOptions options)
|
||||
: base(ArchiveType.GZip, stream, options)
|
||||
{
|
||||
}
|
||||
@@ -161,13 +136,8 @@ namespace SharpCompress.Archive.GZip
|
||||
{
|
||||
}
|
||||
|
||||
public void SaveTo(Stream stream)
|
||||
{
|
||||
SaveTo(stream, CompressionType.GZip);
|
||||
}
|
||||
|
||||
protected override GZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
|
||||
bool closeStream)
|
||||
bool closeStream)
|
||||
{
|
||||
if (Entries.Any())
|
||||
{
|
||||
@@ -176,7 +146,7 @@ namespace SharpCompress.Archive.GZip
|
||||
return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
|
||||
}
|
||||
|
||||
protected override void SaveTo(Stream stream, CompressionInfo compressionInfo,
|
||||
protected override void SaveTo(Stream stream, WriterOptions options,
|
||||
IEnumerable<GZipArchiveEntry> oldEntries,
|
||||
IEnumerable<GZipArchiveEntry> newEntries)
|
||||
{
|
||||
@@ -184,7 +154,7 @@ namespace SharpCompress.Archive.GZip
|
||||
{
|
||||
throw new InvalidOperationException("Only one entry is allowed in a GZip Archive");
|
||||
}
|
||||
using (var writer = new GZipWriter(stream))
|
||||
using (var writer = new GZipWriter(stream, new GZipWriterOptions(options)))
|
||||
{
|
||||
foreach (var entry in oldEntries.Concat(newEntries)
|
||||
.Where(x => !x.IsDirectory))
|
||||
@@ -197,15 +167,15 @@ namespace SharpCompress.Archive.GZip
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<GZipVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
|
||||
protected override IEnumerable<GZipVolume> LoadVolumes(IEnumerable<Stream> streams)
|
||||
{
|
||||
return new GZipVolume(streams.First(), options).AsEnumerable();
|
||||
return new GZipVolume(streams.First(), ReaderOptions).AsEnumerable();
|
||||
}
|
||||
|
||||
protected override IEnumerable<GZipArchiveEntry> LoadEntries(IEnumerable<GZipVolume> volumes)
|
||||
{
|
||||
Stream stream = volumes.Single().Stream;
|
||||
yield return new GZipArchiveEntry(this, new GZipFilePart(stream));
|
||||
yield return new GZipArchiveEntry(this, new GZipFilePart(stream, ReaderOptions.ArchiveEncoding));
|
||||
}
|
||||
|
||||
protected override IReader CreateReaderForSolidExtraction()
|
||||
@@ -2,11 +2,10 @@
|
||||
using System.Linq;
|
||||
using SharpCompress.Common.GZip;
|
||||
|
||||
namespace SharpCompress.Archive.GZip
|
||||
namespace SharpCompress.Archives.GZip
|
||||
{
|
||||
public class GZipArchiveEntry : GZipEntry, IArchiveEntry
|
||||
{
|
||||
|
||||
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part)
|
||||
: base(part)
|
||||
{
|
||||
@@ -15,16 +14,20 @@ namespace SharpCompress.Archive.GZip
|
||||
|
||||
public virtual Stream OpenEntryStream()
|
||||
{
|
||||
//this is to reset the stream to be read multiple times
|
||||
var part = Parts.Single() as GZipFilePart;
|
||||
if (part.GetRawStream().Position != part.EntryStartPosition)
|
||||
{
|
||||
part.GetRawStream().Position = part.EntryStartPosition;
|
||||
}
|
||||
return Parts.Single().GetCompressedStream();
|
||||
}
|
||||
|
||||
#region IArchiveEntry Members
|
||||
public IArchive Archive { get; private set; }
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public IArchive Archive { get; }
|
||||
|
||||
public bool IsComplete => true;
|
||||
|
||||
#endregion
|
||||
}
|
||||
66
src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs
Normal file
66
src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archives.GZip
|
||||
{
|
||||
internal class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry
|
||||
{
|
||||
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;
|
||||
Key = path;
|
||||
Size = size;
|
||||
LastModifiedTime = lastModified;
|
||||
this.closeStream = closeStream;
|
||||
}
|
||||
|
||||
public override long Crc => 0;
|
||||
|
||||
public override string Key { get; }
|
||||
|
||||
public override long CompressedSize => 0;
|
||||
|
||||
public override long Size { get; }
|
||||
|
||||
public override DateTime? LastModifiedTime { get; }
|
||||
|
||||
public override DateTime? CreatedTime => null;
|
||||
|
||||
public override DateTime? LastAccessedTime => null;
|
||||
|
||||
public override DateTime? ArchivedTime => null;
|
||||
|
||||
public override bool IsEncrypted => false;
|
||||
|
||||
public override bool IsDirectory => false;
|
||||
|
||||
public override bool IsSplit => false;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts => throw new NotImplementedException();
|
||||
|
||||
Stream IWritableArchiveEntry.Stream => stream;
|
||||
|
||||
public override Stream OpenEntryStream()
|
||||
{
|
||||
//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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Reader;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public interface IArchive : IDisposable
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public interface IArchiveEntry : IEntry
|
||||
{
|
||||
@@ -1,8 +1,9 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public static class IArchiveEntryExtensions
|
||||
{
|
||||
@@ -28,25 +29,33 @@ namespace SharpCompress.Archive
|
||||
return;
|
||||
}
|
||||
using (entryStream)
|
||||
using (Stream s = new ListeningStream(streamListener, entryStream))
|
||||
{
|
||||
s.TransferTo(streamToWriteTo);
|
||||
using (Stream s = new ListeningStream(streamListener, entryStream))
|
||||
{
|
||||
s.TransferTo(streamToWriteTo);
|
||||
}
|
||||
}
|
||||
streamListener.FireEntryExtractionEnd(archiveEntry);
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory,
|
||||
ExtractOptions options = ExtractOptions.Overwrite)
|
||||
ExtractionOptions options = null)
|
||||
{
|
||||
string destinationFileName;
|
||||
string file = Path.GetFileName(entry.Key);
|
||||
|
||||
options = options ?? new ExtractionOptions()
|
||||
{
|
||||
Overwrite = true
|
||||
};
|
||||
|
||||
if (options.HasFlag(ExtractOptions.ExtractFullPath))
|
||||
|
||||
if (options.ExtractFullPath)
|
||||
{
|
||||
string folder = Path.GetDirectoryName(entry.Key);
|
||||
string destdir = Path.Combine(destinationDirectory, folder);
|
||||
@@ -70,11 +79,16 @@ namespace SharpCompress.Archive
|
||||
/// Extract to specific file
|
||||
/// </summary>
|
||||
public static void WriteToFile(this IArchiveEntry entry, string destinationFileName,
|
||||
ExtractOptions options = ExtractOptions.Overwrite)
|
||||
ExtractionOptions options = null)
|
||||
{
|
||||
FileMode fm = FileMode.Create;
|
||||
options = options ?? new ExtractionOptions()
|
||||
{
|
||||
Overwrite = true
|
||||
};
|
||||
|
||||
if (!options.HasFlag(ExtractOptions.Overwrite))
|
||||
|
||||
if (!options.Overwrite)
|
||||
{
|
||||
fm = FileMode.CreateNew;
|
||||
}
|
||||
@@ -1,16 +1,20 @@
|
||||
using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
#if !NO_FILE
|
||||
using System.Linq;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
#endif
|
||||
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public static class IArchiveExtensions
|
||||
{
|
||||
#if !NO_FILE
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public static void WriteToDirectory(this IArchive archive, string destinationDirectory,
|
||||
ExtractOptions options = ExtractOptions.Overwrite)
|
||||
ExtractionOptions options = null)
|
||||
{
|
||||
foreach (IArchiveEntry entry in archive.Entries.Where(x => !x.IsDirectory))
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
internal interface IArchiveExtractionListener : IExtractionListener
|
||||
{
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public interface IWritableArchive : IArchive
|
||||
{
|
||||
@@ -10,6 +10,6 @@ namespace SharpCompress.Archive
|
||||
|
||||
IArchiveEntry AddEntry(string key, Stream source, bool closeStream, long size = 0, DateTime? modified = null);
|
||||
|
||||
void SaveTo(Stream stream, CompressionInfo compressionType);
|
||||
void SaveTo(Stream stream, WriterOptions options);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
internal interface IWritableArchiveEntry
|
||||
{
|
||||
@@ -1,17 +1,13 @@
|
||||
using System;
|
||||
#if !NO_FILE
|
||||
using System;
|
||||
#endif
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public static class IWritableArchiveExtensions
|
||||
{
|
||||
public static void SaveTo(this IWritableArchive writableArchive,
|
||||
Stream stream, CompressionType compressionType)
|
||||
{
|
||||
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
public static void AddEntry(this IWritableArchive writableArchive,
|
||||
@@ -26,33 +22,16 @@ namespace SharpCompress.Archive
|
||||
fileInfo.LastWriteTime);
|
||||
}
|
||||
|
||||
public static void SaveTo(this IWritableArchive writableArchive,
|
||||
string filePath, CompressionType compressionType)
|
||||
public static void SaveTo(this IWritableArchive writableArchive, string filePath, WriterOptions options)
|
||||
{
|
||||
writableArchive.SaveTo(new FileInfo(filePath), new CompressionInfo {Type = compressionType});
|
||||
writableArchive.SaveTo(new FileInfo(filePath), options);
|
||||
}
|
||||
|
||||
public static void SaveTo(this IWritableArchive writableArchive,
|
||||
FileInfo fileInfo, CompressionType compressionType)
|
||||
public static void SaveTo(this IWritableArchive writableArchive, FileInfo fileInfo, WriterOptions options)
|
||||
{
|
||||
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);
|
||||
writableArchive.SaveTo(stream, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,40 @@
|
||||
#if !NO_FILE
|
||||
|
||||
#if !NO_FILE
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
/// <summary>
|
||||
/// A rar part based on a FileInfo object
|
||||
/// </summary>
|
||||
internal class FileInfoRarArchiveVolume : RarVolume
|
||||
{
|
||||
internal FileInfoRarArchiveVolume(FileInfo fileInfo, string password, Options options)
|
||||
: base(StreamingMode.Seekable, fileInfo.OpenRead(), password, FixOptions(options))
|
||||
internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options)
|
||||
: base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options))
|
||||
{
|
||||
FileInfo = fileInfo;
|
||||
FileParts = base.GetVolumeFileParts().ToReadOnly();
|
||||
FileParts = GetVolumeFileParts().ToReadOnly();
|
||||
}
|
||||
|
||||
private static Options FixOptions(Options options)
|
||||
private static ReaderOptions FixOptions(ReaderOptions options)
|
||||
{
|
||||
//make sure we're closing streams with fileinfo
|
||||
if (options.HasFlag(Options.KeepStreamsOpen))
|
||||
{
|
||||
options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
|
||||
}
|
||||
options.LeaveStreamOpen = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
internal ReadOnlyCollection<RarFilePart> FileParts { get; private set; }
|
||||
internal ReadOnlyCollection<RarFilePart> FileParts { get; }
|
||||
|
||||
internal FileInfo FileInfo { get; private set; }
|
||||
internal FileInfo FileInfo { get; }
|
||||
|
||||
internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader)
|
||||
{
|
||||
return new FileInfoRarFilePart(this, markHeader, fileHeader, FileInfo);
|
||||
return new FileInfoRarFilePart(this, ReaderOptions.Password, markHeader, fileHeader, FileInfo);
|
||||
}
|
||||
|
||||
internal override IEnumerable<RarFilePart> ReadFileParts()
|
||||
@@ -1,19 +1,19 @@
|
||||
#if !NO_FILE
|
||||
|
||||
#if !NO_FILE
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
internal class FileInfoRarFilePart : SeekableFilePart
|
||||
{
|
||||
internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, MarkHeader mh, FileHeader fh, FileInfo fi)
|
||||
: base(mh, fh, volume.Stream, volume.Password)
|
||||
internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, string password, MarkHeader mh, FileHeader fh, FileInfo fi)
|
||||
: base(mh, fh, volume.Stream, password)
|
||||
{
|
||||
FileInfo = fi;
|
||||
}
|
||||
|
||||
internal FileInfo FileInfo { get; private set; }
|
||||
internal FileInfo FileInfo { get; }
|
||||
|
||||
internal override string FilePartName
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
public static class RarArchiveExtensions
|
||||
{
|
||||
@@ -1,41 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using SharpCompress.Compressor.Rar;
|
||||
using SharpCompress.Compressors.Rar;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Reader;
|
||||
using SharpCompress.Reader.Rar;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Rar;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
|
||||
{
|
||||
private readonly Unpack unpack = new Unpack();
|
||||
|
||||
internal Unpack Unpack
|
||||
{
|
||||
get { return unpack; }
|
||||
}
|
||||
internal Unpack Unpack { get; } = new Unpack();
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
internal RarArchive(FileInfo fileInfo, Options options, string password)
|
||||
: base(ArchiveType.Rar, fileInfo, options, password)
|
||||
internal RarArchive(FileInfo fileInfo, ReaderOptions options)
|
||||
: base(ArchiveType.Rar, fileInfo, options)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<RarVolume> LoadVolumes(FileInfo file, Options options)
|
||||
protected override IEnumerable<RarVolume> LoadVolumes(FileInfo file)
|
||||
{
|
||||
return RarArchiveVolumeFactory.GetParts(file, Password, options);
|
||||
return RarArchiveVolumeFactory.GetParts(file, ReaderOptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -44,9 +38,8 @@ namespace SharpCompress.Archive.Rar
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
internal RarArchive(IEnumerable<Stream> streams, Options options, string password)
|
||||
: base(ArchiveType.Rar, streams, options, password)
|
||||
internal RarArchive(IEnumerable<Stream> streams, ReaderOptions options)
|
||||
: base(ArchiveType.Rar, streams, options)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -55,36 +48,33 @@ namespace SharpCompress.Archive.Rar
|
||||
return RarArchiveEntryFactory.GetEntries(this, volumes);
|
||||
}
|
||||
|
||||
protected override IEnumerable<RarVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
|
||||
protected override IEnumerable<RarVolume> LoadVolumes(IEnumerable<Stream> streams)
|
||||
{
|
||||
return RarArchiveVolumeFactory.GetParts(streams, Password, options);
|
||||
return RarArchiveVolumeFactory.GetParts(streams, ReaderOptions);
|
||||
}
|
||||
|
||||
protected override IReader CreateReaderForSolidExtraction()
|
||||
{
|
||||
var stream = Volumes.First().Stream;
|
||||
stream.Position = 0;
|
||||
return RarReader.Open(stream, Password);
|
||||
return RarReader.Open(stream, ReaderOptions);
|
||||
}
|
||||
|
||||
public override bool IsSolid
|
||||
{
|
||||
get { return Volumes.First().IsSolidArchive; }
|
||||
}
|
||||
public override bool IsSolid => Volumes.First().IsSolidArchive;
|
||||
|
||||
#region Creation
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
public static RarArchive Open(string filePath, Options options = Options.None, string password = null)
|
||||
public static RarArchive Open(string filePath, ReaderOptions options = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
return Open(new FileInfo(filePath), options, password);
|
||||
return new RarArchive(new FileInfo(filePath), options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -92,23 +82,22 @@ namespace SharpCompress.Archive.Rar
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
public static RarArchive Open(FileInfo fileInfo, Options options = Options.None, string password = null)
|
||||
public static RarArchive Open(FileInfo fileInfo, ReaderOptions options = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
return new RarArchive(fileInfo, options, password);
|
||||
return new RarArchive(fileInfo, options ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
public static RarArchive Open(Stream stream, Options options = Options.KeepStreamsOpen, string password = null)
|
||||
public static RarArchive Open(Stream stream, ReaderOptions options = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return Open(stream.AsEnumerable(), options, password);
|
||||
return Open(stream.AsEnumerable(), options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -116,11 +105,10 @@ namespace SharpCompress.Archive.Rar
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
public static RarArchive Open(IEnumerable<Stream> streams, Options options = Options.KeepStreamsOpen, string password = null)
|
||||
public static RarArchive Open(IEnumerable<Stream> streams, ReaderOptions options = null)
|
||||
{
|
||||
streams.CheckNotNull("streams");
|
||||
return new RarArchive(streams, options, password);
|
||||
return new RarArchive(streams, options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
@@ -141,17 +129,12 @@ namespace SharpCompress.Archive.Rar
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool IsRarFile(Stream stream)
|
||||
{
|
||||
return IsRarFile(stream, Options.None);
|
||||
}
|
||||
|
||||
public static bool IsRarFile(Stream stream, Options options)
|
||||
|
||||
public static bool IsRarFile(Stream stream, ReaderOptions options = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var headerFactory = new RarHeaderFactory(StreamingMode.Seekable, options);
|
||||
var headerFactory = new RarHeaderFactory(StreamingMode.Seekable, options ?? new ReaderOptions());
|
||||
var markHeader = headerFactory.ReadHeaders(stream).FirstOrDefault() as MarkHeader;
|
||||
return markHeader != null && markHeader.IsValid();
|
||||
}
|
||||
@@ -5,9 +5,9 @@ using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using SharpCompress.Compressor.Rar;
|
||||
using SharpCompress.Compressors.Rar;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
public class RarArchiveEntry : RarEntry, IArchiveEntry
|
||||
{
|
||||
@@ -20,28 +20,13 @@ namespace SharpCompress.Archive.Rar
|
||||
this.archive = archive;
|
||||
}
|
||||
|
||||
public override CompressionType CompressionType
|
||||
{
|
||||
get { return CompressionType.Rar; }
|
||||
}
|
||||
public override CompressionType CompressionType => CompressionType.Rar;
|
||||
|
||||
public IArchive Archive
|
||||
{
|
||||
get
|
||||
{
|
||||
return archive;
|
||||
}
|
||||
}
|
||||
public IArchive Archive => archive;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts
|
||||
{
|
||||
get { return parts.Cast<FilePart>(); }
|
||||
}
|
||||
internal override IEnumerable<FilePart> Parts => parts.Cast<FilePart>();
|
||||
|
||||
internal override FileHeader FileHeader
|
||||
{
|
||||
get { return parts.First().FileHeader; }
|
||||
}
|
||||
internal override FileHeader FileHeader => parts.First().FileHeader;
|
||||
|
||||
public override long Crc
|
||||
{
|
||||
@@ -49,11 +34,10 @@ namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
CheckIncomplete();
|
||||
return parts.Select(fp => fp.FileHeader)
|
||||
.Single(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)).FileCRC;
|
||||
.Single(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)).FileCRC;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override long Size
|
||||
{
|
||||
get
|
||||
@@ -81,10 +65,7 @@ namespace SharpCompress.Archive.Rar
|
||||
return new RarStream(archive.Unpack, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), archive));
|
||||
}
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
get { return parts.Select(fp => fp.FileHeader).Any(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)); }
|
||||
}
|
||||
public bool IsComplete { get { return parts.Select(fp => fp.FileHeader).Any(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)); } }
|
||||
|
||||
private void CheckIncomplete()
|
||||
{
|
||||
@@ -3,7 +3,7 @@ using SharpCompress.Common;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
internal static class RarArchiveEntryFactory
|
||||
{
|
||||
@@ -25,7 +25,7 @@ namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
groupedParts.Add(fp);
|
||||
|
||||
if (!FlagUtility.HasFlag((long) fp.FileHeader.FileFlags, (long) FileFlags.SPLIT_AFTER))
|
||||
if (!FlagUtility.HasFlag((long)fp.FileHeader.FileFlags, (long)FileFlags.SPLIT_AFTER))
|
||||
{
|
||||
yield return groupedParts;
|
||||
groupedParts = new List<RarFilePart>();
|
||||
@@ -1,17 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Readers;
|
||||
#if !NO_FILE
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Rar;
|
||||
#endif
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
internal static class RarArchiveVolumeFactory
|
||||
{
|
||||
internal static IEnumerable<RarVolume> GetParts(IEnumerable<Stream> streams, string password, Options options)
|
||||
internal static IEnumerable<RarVolume> GetParts(IEnumerable<Stream> streams, ReaderOptions options)
|
||||
{
|
||||
foreach (Stream s in streams)
|
||||
{
|
||||
@@ -19,15 +22,15 @@ namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
throw new ArgumentException("Stream is not readable and seekable");
|
||||
}
|
||||
StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, password, options);
|
||||
StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, options);
|
||||
yield return part;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, string password, Options options)
|
||||
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, ReaderOptions options)
|
||||
{
|
||||
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, password, options);
|
||||
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, options);
|
||||
yield return part;
|
||||
|
||||
if (!part.ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME))
|
||||
@@ -39,7 +42,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, password, options);
|
||||
part = new FileInfoRarArchiveVolume(fileInfo, options);
|
||||
|
||||
fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart);
|
||||
yield return part;
|
||||
@@ -1,9 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
internal class SeekableFilePart : RarFilePart
|
||||
{
|
||||
@@ -29,9 +28,6 @@ namespace SharpCompress.Archive.Rar
|
||||
return stream;
|
||||
}
|
||||
|
||||
internal override string FilePartName
|
||||
{
|
||||
get { return "Unknown Stream - File Entry: " + FileHeader.FileName; }
|
||||
}
|
||||
internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
internal class StreamRarArchiveVolume : RarVolume
|
||||
{
|
||||
internal StreamRarArchiveVolume(Stream stream, string password, Options options)
|
||||
: base(StreamingMode.Seekable, stream, password, options)
|
||||
internal StreamRarArchiveVolume(Stream stream, ReaderOptions options)
|
||||
: base(StreamingMode.Seekable, stream, options)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace SharpCompress.Archive.Rar
|
||||
|
||||
internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader)
|
||||
{
|
||||
return new SeekableFilePart(markHeader, fileHeader, Stream, Password);
|
||||
return new SeekableFilePart(markHeader, fileHeader, Stream, ReaderOptions.Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,90 +4,59 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.SevenZip;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Reader;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archive.SevenZip
|
||||
namespace SharpCompress.Archives.SevenZip
|
||||
{
|
||||
public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVolume>
|
||||
{
|
||||
private ArchiveDatabase database;
|
||||
#if !NO_FILE
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
public static SevenZipArchive 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 SevenZipArchive 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 SevenZipArchive Open(string filePath, Options options)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static SevenZipArchive Open(string filePath, ReaderOptions readerOptions = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
return Open(new FileInfo(filePath), options);
|
||||
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
public static SevenZipArchive Open(FileInfo fileInfo, Options options)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
return new SevenZipArchive(fileInfo, options);
|
||||
return new SevenZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
public static SevenZipArchive Open(Stream stream)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return Open(stream, Options.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
public static SevenZipArchive Open(Stream stream, Options options)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return new SevenZipArchive(stream, options);
|
||||
return new SevenZipArchive(stream, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
internal SevenZipArchive(FileInfo fileInfo, Options options)
|
||||
: base(ArchiveType.SevenZip, fileInfo, options, null)
|
||||
internal SevenZipArchive(FileInfo fileInfo, ReaderOptions readerOptions)
|
||||
: base(ArchiveType.SevenZip, fileInfo, readerOptions)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<SevenZipVolume> LoadVolumes(FileInfo file, Options options)
|
||||
protected override IEnumerable<SevenZipVolume> LoadVolumes(FileInfo file)
|
||||
{
|
||||
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
|
||||
{
|
||||
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
|
||||
}
|
||||
return new SevenZipVolume(file.OpenRead(), options).AsEnumerable();
|
||||
return new SevenZipVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
|
||||
}
|
||||
|
||||
public static bool IsSevenZipFile(string filePath)
|
||||
@@ -108,8 +77,8 @@ namespace SharpCompress.Archive.SevenZip
|
||||
}
|
||||
#endif
|
||||
|
||||
internal SevenZipArchive(Stream stream, Options options)
|
||||
: base(ArchiveType.SevenZip, stream.AsEnumerable(), options, null)
|
||||
internal SevenZipArchive(Stream stream, ReaderOptions readerOptions)
|
||||
: base(ArchiveType.SevenZip, stream.AsEnumerable(), readerOptions)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -118,7 +87,7 @@ namespace SharpCompress.Archive.SevenZip
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<SevenZipVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
|
||||
protected override IEnumerable<SevenZipVolume> LoadVolumes(IEnumerable<Stream> streams)
|
||||
{
|
||||
foreach (Stream s in streams)
|
||||
{
|
||||
@@ -126,7 +95,7 @@ namespace SharpCompress.Archive.SevenZip
|
||||
{
|
||||
throw new ArgumentException("Stream is not readable and seekable");
|
||||
}
|
||||
SevenZipVolume volume = new SevenZipVolume(s, options);
|
||||
SevenZipVolume volume = new SevenZipVolume(s, ReaderOptions);
|
||||
yield return volume;
|
||||
}
|
||||
}
|
||||
@@ -138,10 +107,7 @@ namespace SharpCompress.Archive.SevenZip
|
||||
for (int i = 0; i < database.Files.Count; i++)
|
||||
{
|
||||
var file = database.Files[i];
|
||||
if (!file.IsDir)
|
||||
{
|
||||
yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file));
|
||||
}
|
||||
yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,11 +118,10 @@ namespace SharpCompress.Archive.SevenZip
|
||||
stream.Position = 0;
|
||||
var reader = new ArchiveReader();
|
||||
reader.Open(stream);
|
||||
database = reader.ReadDatabase(null);
|
||||
database = reader.ReadDatabase(new PasswordProvider(ReaderOptions.Password));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool IsSevenZipFile(Stream stream)
|
||||
{
|
||||
try
|
||||
@@ -169,7 +134,7 @@ namespace SharpCompress.Archive.SevenZip
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly byte[] SIGNATURE = new byte[] {(byte) '7', (byte) 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
||||
private static readonly byte[] SIGNATURE = {(byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C};
|
||||
|
||||
private static bool SignatureMatch(Stream stream)
|
||||
{
|
||||
@@ -180,13 +145,10 @@ namespace SharpCompress.Archive.SevenZip
|
||||
|
||||
protected override IReader CreateReaderForSolidExtraction()
|
||||
{
|
||||
return new SevenZipReader(this);
|
||||
return new SevenZipReader(ReaderOptions, this);
|
||||
}
|
||||
|
||||
public override bool IsSolid
|
||||
{
|
||||
get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; }
|
||||
}
|
||||
public override bool IsSolid { get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; } }
|
||||
|
||||
public override long TotalSize
|
||||
{
|
||||
@@ -204,17 +166,13 @@ namespace SharpCompress.Archive.SevenZip
|
||||
private Stream currentStream;
|
||||
private CFileItem currentItem;
|
||||
|
||||
internal SevenZipReader(SevenZipArchive archive)
|
||||
: base(Options.KeepStreamsOpen, ArchiveType.SevenZip)
|
||||
internal SevenZipReader(ReaderOptions readerOptions, SevenZipArchive archive)
|
||||
: base(readerOptions, ArchiveType.SevenZip)
|
||||
{
|
||||
this.archive = archive;
|
||||
}
|
||||
|
||||
|
||||
public override SevenZipVolume Volume
|
||||
{
|
||||
get { return archive.Volumes.Single(); }
|
||||
}
|
||||
public override SevenZipVolume Volume => archive.Volumes.Single();
|
||||
|
||||
internal override IEnumerable<SevenZipEntry> GetEntries(Stream stream)
|
||||
{
|
||||
@@ -233,7 +191,7 @@ namespace SharpCompress.Archive.SevenZip
|
||||
}
|
||||
else
|
||||
{
|
||||
currentStream = archive.database.GetFolderStream(stream, currentFolder, null);
|
||||
currentStream = archive.database.GetFolderStream(stream, currentFolder, new PasswordProvider(Options.Password));
|
||||
}
|
||||
foreach (var entry in group)
|
||||
{
|
||||
@@ -248,5 +206,21 @@ namespace SharpCompress.Archive.SevenZip
|
||||
return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size));
|
||||
}
|
||||
}
|
||||
|
||||
private class PasswordProvider : IPasswordProvider
|
||||
{
|
||||
private readonly string _password;
|
||||
|
||||
public PasswordProvider(string password)
|
||||
{
|
||||
_password = password;
|
||||
|
||||
}
|
||||
|
||||
public string CryptoGetTextPassword()
|
||||
{
|
||||
return _password;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.SevenZip;
|
||||
|
||||
namespace SharpCompress.Archive.SevenZip
|
||||
namespace SharpCompress.Archives.SevenZip
|
||||
{
|
||||
public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry
|
||||
{
|
||||
@@ -16,19 +15,14 @@ namespace SharpCompress.Archive.SevenZip
|
||||
{
|
||||
return FilePart.GetCompressedStream();
|
||||
}
|
||||
public IArchive Archive { get; private set; }
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public IArchive Archive { get; }
|
||||
|
||||
public bool IsComplete => true;
|
||||
|
||||
/// <summary>
|
||||
/// This is a 7Zip Anti item
|
||||
/// </summary>
|
||||
public bool IsAnti
|
||||
{
|
||||
get { return FilePart.Header.IsAnti; }
|
||||
}
|
||||
public bool IsAnti => FilePart.Header.IsAnti;
|
||||
}
|
||||
}
|
||||
@@ -6,53 +6,37 @@ using SharpCompress.Common;
|
||||
using SharpCompress.Common.Tar;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Reader;
|
||||
using SharpCompress.Reader.Tar;
|
||||
using SharpCompress.Writer.Tar;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Tar;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.Tar;
|
||||
|
||||
namespace SharpCompress.Archive.Tar
|
||||
namespace SharpCompress.Archives.Tar
|
||||
{
|
||||
public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
{
|
||||
#if !NO_FILE
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
public static TarArchive 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 TarArchive 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 TarArchive Open(string filePath, Options options)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static TarArchive Open(string filePath, ReaderOptions readerOptions = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
return Open(new FileInfo(filePath), options);
|
||||
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
public static TarArchive Open(FileInfo fileInfo, Options options)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static TarArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
return new TarArchive(fileInfo, options);
|
||||
return new TarArchive(fileInfo, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -60,24 +44,15 @@ namespace SharpCompress.Archive.Tar
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
public static TarArchive Open(Stream stream)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static TarArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return Open(stream, Options.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
public static TarArchive Open(Stream stream, Options options)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return new TarArchive(stream, options);
|
||||
return new TarArchive(stream, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
public static bool IsTarFile(string filePath)
|
||||
{
|
||||
return IsTarFile(new FileInfo(filePath));
|
||||
@@ -100,9 +75,9 @@ namespace SharpCompress.Archive.Tar
|
||||
{
|
||||
try
|
||||
{
|
||||
TarHeader tar = new TarHeader();
|
||||
TarHeader tar = new TarHeader(new ArchiveEncoding());
|
||||
tar.Read(new BinaryReader(stream));
|
||||
return tar.Name.Length > 0 && Enum.IsDefined(typeof (EntryType), tar.EntryType);
|
||||
return tar.Name.Length > 0 && Enum.IsDefined(typeof(EntryType), tar.EntryType);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -111,23 +86,20 @@ namespace SharpCompress.Archive.Tar
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
internal TarArchive(FileInfo fileInfo, Options options)
|
||||
: base(ArchiveType.Tar, fileInfo, options)
|
||||
/// <param name="readerOptions"></param>
|
||||
internal TarArchive(FileInfo fileInfo, ReaderOptions readerOptions)
|
||||
: base(ArchiveType.Tar, fileInfo, readerOptions)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<TarVolume> LoadVolumes(FileInfo file, Options options)
|
||||
protected override IEnumerable<TarVolume> LoadVolumes(FileInfo file)
|
||||
{
|
||||
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
|
||||
{
|
||||
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
|
||||
}
|
||||
return new TarVolume(file.OpenRead(), options).AsEnumerable();
|
||||
return new TarVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -135,9 +107,9 @@ namespace SharpCompress.Archive.Tar
|
||||
/// Takes multiple seekable Streams for a multi-part archive
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
internal TarArchive(Stream stream, Options options)
|
||||
: base(ArchiveType.Tar, stream, options)
|
||||
/// <param name="readerOptions"></param>
|
||||
internal TarArchive(Stream stream, ReaderOptions readerOptions)
|
||||
: base(ArchiveType.Tar, stream, readerOptions)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -146,16 +118,16 @@ namespace SharpCompress.Archive.Tar
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<TarVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
|
||||
protected override IEnumerable<TarVolume> LoadVolumes(IEnumerable<Stream> streams)
|
||||
{
|
||||
return new TarVolume(streams.First(), options).AsEnumerable();
|
||||
return new TarVolume(streams.First(), ReaderOptions).AsEnumerable();
|
||||
}
|
||||
|
||||
protected override IEnumerable<TarArchiveEntry> LoadEntries(IEnumerable<TarVolume> volumes)
|
||||
{
|
||||
Stream stream = volumes.Single().Stream;
|
||||
TarHeader previousHeader = null;
|
||||
foreach (TarHeader header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream))
|
||||
foreach (TarHeader header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream, ReaderOptions.ArchiveEncoding))
|
||||
{
|
||||
if (header != null)
|
||||
{
|
||||
@@ -172,14 +144,16 @@ namespace SharpCompress.Archive.Tar
|
||||
|
||||
var oldStreamPos = stream.Position;
|
||||
|
||||
using(var entryStream = entry.OpenEntryStream())
|
||||
using(var memoryStream = new MemoryStream())
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
entryStream.TransferTo(memoryStream);
|
||||
memoryStream.Position = 0;
|
||||
var bytes = memoryStream.ToArray();
|
||||
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();
|
||||
header.Name = ReaderOptions.ArchiveEncoding.Decode(bytes).TrimNulls();
|
||||
}
|
||||
}
|
||||
|
||||
stream.Position = oldStreamPos;
|
||||
@@ -198,17 +172,17 @@ namespace SharpCompress.Archive.Tar
|
||||
}
|
||||
|
||||
protected override TarArchiveEntry CreateEntryInternal(string filePath, Stream source,
|
||||
long size, DateTime? modified, bool closeStream)
|
||||
long size, DateTime? modified, bool closeStream)
|
||||
{
|
||||
return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified,
|
||||
closeStream);
|
||||
}
|
||||
|
||||
protected override void SaveTo(Stream stream, CompressionInfo compressionInfo,
|
||||
protected override void SaveTo(Stream stream, WriterOptions options,
|
||||
IEnumerable<TarArchiveEntry> oldEntries,
|
||||
IEnumerable<TarArchiveEntry> newEntries)
|
||||
{
|
||||
using (var writer = new TarWriter(stream, compressionInfo))
|
||||
using (var writer = new TarWriter(stream, new TarWriterOptions(options)))
|
||||
{
|
||||
foreach (var entry in oldEntries.Concat(newEntries)
|
||||
.Where(x => !x.IsDirectory))
|
||||
@@ -3,7 +3,7 @@ using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Tar;
|
||||
|
||||
namespace SharpCompress.Archive.Tar
|
||||
namespace SharpCompress.Archives.Tar
|
||||
{
|
||||
public class TarArchiveEntry : TarEntry, IArchiveEntry
|
||||
{
|
||||
@@ -19,12 +19,10 @@ namespace SharpCompress.Archive.Tar
|
||||
}
|
||||
|
||||
#region IArchiveEntry Members
|
||||
public IArchive Archive { get; private set; }
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public IArchive Archive { get; }
|
||||
|
||||
public bool IsComplete => true;
|
||||
|
||||
#endregion
|
||||
}
|
||||
65
src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs
Normal file
65
src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archives.Tar
|
||||
{
|
||||
internal class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry
|
||||
{
|
||||
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;
|
||||
Key = path;
|
||||
Size = size;
|
||||
LastModifiedTime = lastModified;
|
||||
this.closeStream = closeStream;
|
||||
}
|
||||
|
||||
public override long Crc => 0;
|
||||
|
||||
public override string Key { get; }
|
||||
|
||||
public override long CompressedSize => 0;
|
||||
|
||||
public override long Size { get; }
|
||||
|
||||
public override DateTime? LastModifiedTime { get; }
|
||||
|
||||
public override DateTime? CreatedTime => null;
|
||||
|
||||
public override DateTime? LastAccessedTime => null;
|
||||
|
||||
public override DateTime? ArchivedTime => null;
|
||||
|
||||
public override bool IsEncrypted => false;
|
||||
|
||||
public override bool IsDirectory => false;
|
||||
|
||||
public override bool IsSplit => false;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts => throw new NotImplementedException();
|
||||
Stream IWritableArchiveEntry.Stream => stream;
|
||||
|
||||
public override Stream OpenEntryStream()
|
||||
{
|
||||
//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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,13 @@ using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Zip;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressor.Deflate;
|
||||
using SharpCompress.Reader;
|
||||
using SharpCompress.Reader.Zip;
|
||||
using SharpCompress.Writer.Zip;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Zip;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.Zip;
|
||||
|
||||
namespace SharpCompress.Archive.Zip
|
||||
namespace SharpCompress.Archives.Zip
|
||||
{
|
||||
public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
{
|
||||
@@ -23,48 +24,27 @@ namespace SharpCompress.Archive.Zip
|
||||
public CompressionLevel DeflateCompressionLevel { get; set; }
|
||||
|
||||
#if !NO_FILE
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="password"></param>
|
||||
public static ZipArchive Open(string filePath, string password = null)
|
||||
{
|
||||
return Open(filePath, Options.None, password);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="password"></param>
|
||||
public static ZipArchive Open(FileInfo fileInfo, string password = null)
|
||||
{
|
||||
return Open(fileInfo, Options.None, password);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
public static ZipArchive Open(string filePath, Options options, string password = null)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static ZipArchive Open(string filePath, ReaderOptions readerOptions = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
return Open(new FileInfo(filePath), options, password);
|
||||
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
public static ZipArchive Open(FileInfo fileInfo, Options options, string password = null)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static ZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
return new ZipArchive(fileInfo, options, password);
|
||||
return new ZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -72,26 +52,15 @@ namespace SharpCompress.Archive.Zip
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="password"></param>
|
||||
public static ZipArchive Open(Stream stream, string password = null)
|
||||
/// <param name="readerOptions"></param>
|
||||
public static ZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return Open(stream, Options.None, password);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
public static ZipArchive Open(Stream stream, Options options, string password = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return new ZipArchive(stream, options, password);
|
||||
return new ZipArchive(stream, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
public static bool IsZipFile(string filePath, string password = null)
|
||||
{
|
||||
return IsZipFile(new FileInfo(filePath), password);
|
||||
@@ -112,7 +81,7 @@ namespace SharpCompress.Archive.Zip
|
||||
|
||||
public static bool IsZipFile(Stream stream, string password = null)
|
||||
{
|
||||
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password);
|
||||
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding());
|
||||
try
|
||||
{
|
||||
ZipHeader header =
|
||||
@@ -121,7 +90,7 @@ namespace SharpCompress.Archive.Zip
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Enum.IsDefined(typeof (ZipHeaderType), header.ZipHeaderType);
|
||||
return Enum.IsDefined(typeof(ZipHeaderType), header.ZipHeaderType);
|
||||
}
|
||||
catch (CryptographicException)
|
||||
{
|
||||
@@ -134,25 +103,21 @@ namespace SharpCompress.Archive.Zip
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
internal ZipArchive(FileInfo fileInfo, Options options, string password = null)
|
||||
: base(ArchiveType.Zip, fileInfo, options)
|
||||
/// <param name="readerOptions"></param>
|
||||
internal ZipArchive(FileInfo fileInfo, ReaderOptions readerOptions)
|
||||
: base(ArchiveType.Zip, fileInfo, readerOptions)
|
||||
{
|
||||
headerFactory = new SeekableZipHeaderFactory(password);
|
||||
headerFactory = new SeekableZipHeaderFactory(readerOptions.Password, readerOptions.ArchiveEncoding);
|
||||
}
|
||||
|
||||
protected override IEnumerable<ZipVolume> LoadVolumes(FileInfo file, Options options)
|
||||
protected override IEnumerable<ZipVolume> LoadVolumes(FileInfo file)
|
||||
{
|
||||
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
|
||||
{
|
||||
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
|
||||
}
|
||||
return new ZipVolume(file.OpenRead(), options).AsEnumerable();
|
||||
return new ZipVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -165,17 +130,16 @@ namespace SharpCompress.Archive.Zip
|
||||
/// Takes multiple seekable Streams for a multi-part archive
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
internal ZipArchive(Stream stream, Options options, string password = null)
|
||||
: base(ArchiveType.Zip, stream, options)
|
||||
/// <param name="readerOptions"></param>
|
||||
internal ZipArchive(Stream stream, ReaderOptions readerOptions)
|
||||
: base(ArchiveType.Zip, stream, readerOptions)
|
||||
{
|
||||
headerFactory = new SeekableZipHeaderFactory(password);
|
||||
headerFactory = new SeekableZipHeaderFactory(readerOptions.Password, readerOptions.ArchiveEncoding);
|
||||
}
|
||||
|
||||
protected override IEnumerable<ZipVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
|
||||
protected override IEnumerable<ZipVolume> LoadVolumes(IEnumerable<Stream> streams)
|
||||
{
|
||||
return new ZipVolume(streams.First(), options).AsEnumerable();
|
||||
return new ZipVolume(streams.First(), ReaderOptions).AsEnumerable();
|
||||
}
|
||||
|
||||
protected override IEnumerable<ZipArchiveEntry> LoadEntries(IEnumerable<ZipVolume> volumes)
|
||||
@@ -199,7 +163,7 @@ namespace SharpCompress.Archive.Zip
|
||||
case ZipHeaderType.DirectoryEnd:
|
||||
{
|
||||
byte[] bytes = (h as DirectoryEndHeader).Comment;
|
||||
volume.Comment = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length);
|
||||
volume.Comment = ReaderOptions.ArchiveEncoding.Decode(bytes);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
@@ -207,25 +171,30 @@ namespace SharpCompress.Archive.Zip
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SaveTo(Stream stream, CompressionInfo compressionInfo,
|
||||
public void SaveTo(Stream stream)
|
||||
{
|
||||
SaveTo(stream, new WriterOptions(CompressionType.Deflate));
|
||||
}
|
||||
|
||||
protected override void SaveTo(Stream stream, WriterOptions options,
|
||||
IEnumerable<ZipArchiveEntry> oldEntries,
|
||||
IEnumerable<ZipArchiveEntry> newEntries)
|
||||
{
|
||||
using (var writer = new ZipWriter(stream, compressionInfo, string.Empty))
|
||||
using (var writer = new ZipWriter(stream, new ZipWriterOptions(options)))
|
||||
{
|
||||
foreach (var entry in oldEntries.Concat(newEntries)
|
||||
.Where(x => !x.IsDirectory))
|
||||
{
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
writer.Write(entry.Key, entryStream, entry.LastModifiedTime, string.Empty);
|
||||
writer.Write(entry.Key, entryStream, entry.LastModifiedTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override ZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
|
||||
bool closeStream)
|
||||
bool closeStream)
|
||||
{
|
||||
return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
|
||||
}
|
||||
@@ -239,7 +208,7 @@ namespace SharpCompress.Archive.Zip
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return ZipReader.Open(stream);
|
||||
return ZipReader.Open(stream, ReaderOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Linq;
|
||||
using SharpCompress.Common.Zip;
|
||||
|
||||
namespace SharpCompress.Archive.Zip
|
||||
namespace SharpCompress.Archives.Zip
|
||||
{
|
||||
public class ZipArchiveEntry : ZipEntry, IArchiveEntry
|
||||
{
|
||||
@@ -19,18 +19,12 @@ namespace SharpCompress.Archive.Zip
|
||||
|
||||
#region IArchiveEntry Members
|
||||
|
||||
public IArchive Archive { get; private set; }
|
||||
public IArchive Archive { get; }
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public bool IsComplete => true;
|
||||
|
||||
#endregion
|
||||
|
||||
public string Comment
|
||||
{
|
||||
get { return (Parts.Single() as SeekableZipFilePart).Comment; }
|
||||
}
|
||||
public string Comment => (Parts.Single() as SeekableZipFilePart).Comment;
|
||||
}
|
||||
}
|
||||
68
src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs
Normal file
68
src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archives.Zip
|
||||
{
|
||||
internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
|
||||
{
|
||||
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;
|
||||
Key = path;
|
||||
Size = size;
|
||||
LastModifiedTime = lastModified;
|
||||
this.closeStream = closeStream;
|
||||
}
|
||||
|
||||
public override long Crc => 0;
|
||||
|
||||
public override string Key { get; }
|
||||
|
||||
public override long CompressedSize => 0;
|
||||
|
||||
public override long Size { get; }
|
||||
|
||||
public override DateTime? LastModifiedTime { get; }
|
||||
|
||||
public override DateTime? CreatedTime => null;
|
||||
|
||||
public override DateTime? LastAccessedTime => null;
|
||||
|
||||
public override DateTime? ArchivedTime => null;
|
||||
|
||||
public override bool IsEncrypted => false;
|
||||
|
||||
public override bool IsDirectory => false;
|
||||
|
||||
public override bool IsSplit => false;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts => throw new NotImplementedException();
|
||||
|
||||
Stream IWritableArchiveEntry.Stream => stream;
|
||||
|
||||
public override Stream OpenEntryStream()
|
||||
{
|
||||
//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 && !isDisposed)
|
||||
{
|
||||
stream.Dispose();
|
||||
isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,24 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
|
||||
[assembly: AssemblyTitle("SharpCompress")]
|
||||
[assembly: AssemblyProduct("SharpCompress")]
|
||||
|
||||
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test")]
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test.Portable")]
|
||||
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test" + SharpCompress.AssemblyInfo.PublicKeySuffix)]
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test.Portable" + SharpCompress.AssemblyInfo.PublicKeySuffix)]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
namespace SharpCompress
|
||||
{
|
||||
/// <summary>
|
||||
/// Just a static class to house the public key, to avoid repetition.
|
||||
/// </summary>
|
||||
internal static class AssemblyInfo
|
||||
{
|
||||
internal const string PublicKeySuffix =
|
||||
",PublicKey=002400000480000094000000060200000024000052534131000400000100010059acfa17d26c44" +
|
||||
"7a4d03f16eaa72c9187c04f16e6569dd168b080e39a6f5c9fd00f28c768cd8e9a089d5a0e1b34c" +
|
||||
"cd971488e7afe030ce5ce8df2053cf12ec89f6d38065c434c09ee6af3ee284c5dc08f44774b679" +
|
||||
"bf39298e57efe30d4b00aecf9e4f6f8448b2cb0146d8956dfcab606cc64a0ac38c60a7d78b0d65" +
|
||||
"d3b98dc0";
|
||||
}
|
||||
}
|
||||
|
||||
119
src/SharpCompress/Buffers/ArrayPool.cs
Normal file
119
src/SharpCompress/Buffers/ArrayPool.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
#if NETCORE
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpCompress.Buffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a resource pool that enables reusing instances of type <see cref="T:T[]"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Renting and returning buffers with an <see cref="ArrayPool{T}"/> can increase performance
|
||||
/// in situations where arrays are created and destroyed frequently, resulting in significant
|
||||
/// memory pressure on the garbage collector.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This class is thread-safe. All members may be used by multiple threads concurrently.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
internal abstract class ArrayPool<T>
|
||||
{
|
||||
/// <summary>The lazily-initialized shared pool instance.</summary>
|
||||
private static ArrayPool<T> s_sharedInstance = null;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a shared <see cref="ArrayPool{T}"/> instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The shared pool provides a default implementation of <see cref="ArrayPool{T}"/>
|
||||
/// that's intended for general applicability. It maintains arrays of multiple sizes, and
|
||||
/// may hand back a larger array than was actually requested, but will never hand back a smaller
|
||||
/// array than was requested. Renting a buffer from it with <see cref="Rent"/> will result in an
|
||||
/// existing buffer being taken from the pool if an appropriate buffer is available or in a new
|
||||
/// buffer being allocated if one is not available.
|
||||
/// </remarks>
|
||||
public static ArrayPool<T> Shared
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return Volatile.Read(ref s_sharedInstance) ?? EnsureSharedCreated(); }
|
||||
}
|
||||
|
||||
/// <summary>Ensures that <see cref="s_sharedInstance"/> has been initialized to a pool and returns it.</summary>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static ArrayPool<T> EnsureSharedCreated()
|
||||
{
|
||||
Interlocked.CompareExchange(ref s_sharedInstance, Create(), null);
|
||||
return s_sharedInstance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ArrayPool{T}"/> instance using default configuration options.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="ArrayPool{T}"/> instance.</returns>
|
||||
public static ArrayPool<T> Create()
|
||||
{
|
||||
return new DefaultArrayPool<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ArrayPool{T}"/> instance using custom configuration options.
|
||||
/// </summary>
|
||||
/// <param name="maxArrayLength">The maximum length of array instances that may be stored in the pool.</param>
|
||||
/// <param name="maxArraysPerBucket">
|
||||
/// The maximum number of array instances that may be stored in each bucket in the pool. The pool
|
||||
/// groups arrays of similar lengths into buckets for faster access.
|
||||
/// </param>
|
||||
/// <returns>A new <see cref="ArrayPool{T}"/> instance with the specified configuration options.</returns>
|
||||
/// <remarks>
|
||||
/// The created pool will group arrays into buckets, with no more than <paramref name="maxArraysPerBucket"/>
|
||||
/// in each bucket and with those arrays not exceeding <paramref name="maxArrayLength"/> in length.
|
||||
/// </remarks>
|
||||
public static ArrayPool<T> Create(int maxArrayLength, int maxArraysPerBucket)
|
||||
{
|
||||
return new DefaultArrayPool<T>(maxArrayLength, maxArraysPerBucket);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a buffer that is at least the requested length.
|
||||
/// </summary>
|
||||
/// <param name="minimumLength">The minimum length of the array needed.</param>
|
||||
/// <returns>
|
||||
/// An <see cref="T:T[]"/> that is at least <paramref name="minimumLength"/> in length.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This buffer is loaned to the caller and should be returned to the same pool via
|
||||
/// <see cref="Return"/> so that it may be reused in subsequent usage of <see cref="Rent"/>.
|
||||
/// It is not a fatal error to not return a rented buffer, but failure to do so may lead to
|
||||
/// decreased application performance, as the pool may need to create a new buffer to replace
|
||||
/// the one lost.
|
||||
/// </remarks>
|
||||
public abstract T[] Rent(int minimumLength);
|
||||
|
||||
/// <summary>
|
||||
/// Returns to the pool an array that was previously obtained via <see cref="Rent"/> on the same
|
||||
/// <see cref="ArrayPool{T}"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="array">
|
||||
/// The buffer previously obtained from <see cref="Rent"/> to return to the pool.
|
||||
/// </param>
|
||||
/// <param name="clearArray">
|
||||
/// If <c>true</c> and if the pool will store the buffer to enable subsequent reuse, <see cref="Return"/>
|
||||
/// will clear <paramref name="array"/> of its contents so that a subsequent consumer via <see cref="Rent"/>
|
||||
/// will not see the previous consumer's content. If <c>false</c> or if the pool will release the buffer,
|
||||
/// the array's contents are left unchanged.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Once a buffer has been returned to the pool, the caller gives up all ownership of the buffer
|
||||
/// and must not use it. The reference returned from a given call to <see cref="Rent"/> must only be
|
||||
/// returned via <see cref="Return"/> once. The default <see cref="ArrayPool{T}"/>
|
||||
/// may hold onto the returned buffer in order to rent it again, or it may release the returned buffer
|
||||
/// if it's determined that the pool already has enough buffers stored.
|
||||
/// </remarks>
|
||||
public abstract void Return(T[] array, bool clearArray = false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
144
src/SharpCompress/Buffers/DefaultArrayPool.cs
Normal file
144
src/SharpCompress/Buffers/DefaultArrayPool.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
#if NETCORE
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Buffers
|
||||
{
|
||||
internal sealed partial class DefaultArrayPool<T> : ArrayPool<T>
|
||||
{
|
||||
/// <summary>The default maximum length of each array in the pool (2^20).</summary>
|
||||
private const int DefaultMaxArrayLength = 1024 * 1024;
|
||||
/// <summary>The default maximum number of arrays per bucket that are available for rent.</summary>
|
||||
private const int DefaultMaxNumberOfArraysPerBucket = 50;
|
||||
/// <summary>Lazily-allocated empty array used when arrays of length 0 are requested.</summary>
|
||||
private static T[] s_emptyArray; // we support contracts earlier than those with Array.Empty<T>()
|
||||
|
||||
private readonly Bucket[] _buckets;
|
||||
|
||||
internal DefaultArrayPool() : this(DefaultMaxArrayLength, DefaultMaxNumberOfArraysPerBucket)
|
||||
{
|
||||
}
|
||||
|
||||
internal DefaultArrayPool(int maxArrayLength, int maxArraysPerBucket)
|
||||
{
|
||||
if (maxArrayLength <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxArrayLength));
|
||||
}
|
||||
if (maxArraysPerBucket <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxArraysPerBucket));
|
||||
}
|
||||
|
||||
// Our bucketing algorithm has a min length of 2^4 and a max length of 2^30.
|
||||
// Constrain the actual max used to those values.
|
||||
const int MinimumArrayLength = 0x10, MaximumArrayLength = 0x40000000;
|
||||
if (maxArrayLength > MaximumArrayLength)
|
||||
{
|
||||
maxArrayLength = MaximumArrayLength;
|
||||
}
|
||||
else if (maxArrayLength < MinimumArrayLength)
|
||||
{
|
||||
maxArrayLength = MinimumArrayLength;
|
||||
}
|
||||
|
||||
// Create the buckets.
|
||||
int poolId = Id;
|
||||
int maxBuckets = Utilities.SelectBucketIndex(maxArrayLength);
|
||||
var buckets = new Bucket[maxBuckets + 1];
|
||||
for (int i = 0; i < buckets.Length; i++)
|
||||
{
|
||||
buckets[i] = new Bucket(Utilities.GetMaxSizeForBucket(i), maxArraysPerBucket, poolId);
|
||||
}
|
||||
_buckets = buckets;
|
||||
}
|
||||
|
||||
/// <summary>Gets an ID for the pool to use with events.</summary>
|
||||
private int Id => GetHashCode();
|
||||
|
||||
public override T[] Rent(int minimumLength)
|
||||
{
|
||||
// Arrays can't be smaller than zero. We allow requesting zero-length arrays (even though
|
||||
// pooling such an array isn't valuable) as it's a valid length array, and we want the pool
|
||||
// to be usable in general instead of using `new`, even for computed lengths.
|
||||
if (minimumLength < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(minimumLength));
|
||||
}
|
||||
else if (minimumLength == 0)
|
||||
{
|
||||
// No need for events with the empty array. Our pool is effectively infinite
|
||||
// and we'll never allocate for rents and never store for returns.
|
||||
return s_emptyArray ?? (s_emptyArray = new T[0]);
|
||||
}
|
||||
|
||||
T[] buffer = null;
|
||||
|
||||
int index = Utilities.SelectBucketIndex(minimumLength);
|
||||
if (index < _buckets.Length)
|
||||
{
|
||||
// Search for an array starting at the 'index' bucket. If the bucket is empty, bump up to the
|
||||
// next higher bucket and try that one, but only try at most a few buckets.
|
||||
const int MaxBucketsToTry = 2;
|
||||
int i = index;
|
||||
do
|
||||
{
|
||||
// Attempt to rent from the bucket. If we get a buffer from it, return it.
|
||||
buffer = _buckets[i].Rent();
|
||||
if (buffer != null)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
while (++i < _buckets.Length && i != index + MaxBucketsToTry);
|
||||
|
||||
// The pool was exhausted for this buffer size. Allocate a new buffer with a size corresponding
|
||||
// to the appropriate bucket.
|
||||
buffer = new T[_buckets[index]._bufferLength];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The request was for a size too large for the pool. Allocate an array of exactly the requested length.
|
||||
// When it's returned to the pool, we'll simply throw it away.
|
||||
buffer = new T[minimumLength];
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public override void Return(T[] array, bool clearArray = false)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
}
|
||||
else if (array.Length == 0)
|
||||
{
|
||||
// Ignore empty arrays. When a zero-length array is rented, we return a singleton
|
||||
// rather than actually taking a buffer out of the lowest bucket.
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine with what bucket this array length is associated
|
||||
int bucket = Utilities.SelectBucketIndex(array.Length);
|
||||
|
||||
// If we can tell that the buffer was allocated, drop it. Otherwise, check if we have space in the pool
|
||||
if (bucket < _buckets.Length)
|
||||
{
|
||||
// Clear the array if the user requests
|
||||
if (clearArray)
|
||||
{
|
||||
Array.Clear(array, 0, array.Length);
|
||||
}
|
||||
|
||||
// Return the buffer to its bucket. In the future, we might consider having Return return false
|
||||
// instead of dropping a bucket, in which case we could try to return to a lower-sized bucket,
|
||||
// just as how in Rent we allow renting from a higher-sized bucket.
|
||||
_buckets[bucket].Return(array);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
111
src/SharpCompress/Buffers/DefaultArrayPoolBucket.cs
Normal file
111
src/SharpCompress/Buffers/DefaultArrayPoolBucket.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#if NETCORE
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpCompress.Buffers
|
||||
{
|
||||
internal sealed partial class DefaultArrayPool<T> : ArrayPool<T>
|
||||
{
|
||||
/// <summary>Provides a thread-safe bucket containing buffers that can be Rent'd and Return'd.</summary>
|
||||
private sealed class Bucket
|
||||
{
|
||||
internal readonly int _bufferLength;
|
||||
private readonly T[][] _buffers;
|
||||
private readonly int _poolId;
|
||||
|
||||
private SpinLock _lock; // do not make this readonly; it's a mutable struct
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the pool with numberOfBuffers arrays where each buffer is of bufferLength length.
|
||||
/// </summary>
|
||||
internal Bucket(int bufferLength, int numberOfBuffers, int poolId)
|
||||
{
|
||||
_lock = new SpinLock(Debugger.IsAttached); // only enable thread tracking if debugger is attached; it adds non-trivial overheads to Enter/Exit
|
||||
_buffers = new T[numberOfBuffers][];
|
||||
_bufferLength = bufferLength;
|
||||
_poolId = poolId;
|
||||
}
|
||||
|
||||
/// <summary>Gets an ID for the bucket to use with events.</summary>
|
||||
internal int Id => GetHashCode();
|
||||
|
||||
/// <summary>Takes an array from the bucket. If the bucket is empty, returns null.</summary>
|
||||
internal T[] Rent()
|
||||
{
|
||||
T[][] buffers = _buffers;
|
||||
T[] buffer = null;
|
||||
|
||||
// While holding the lock, grab whatever is at the next available index and
|
||||
// update the index. We do as little work as possible while holding the spin
|
||||
// lock to minimize contention with other threads. The try/finally is
|
||||
// necessary to properly handle thread aborts on platforms which have them.
|
||||
bool lockTaken = false, allocateBuffer = false;
|
||||
try
|
||||
{
|
||||
_lock.Enter(ref lockTaken);
|
||||
|
||||
if (_index < buffers.Length)
|
||||
{
|
||||
buffer = buffers[_index];
|
||||
buffers[_index++] = null;
|
||||
allocateBuffer = buffer == null;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken) _lock.Exit(false);
|
||||
}
|
||||
|
||||
// While we were holding the lock, we grabbed whatever was at the next available index, if
|
||||
// there was one. If we tried and if we got back null, that means we hadn't yet allocated
|
||||
// for that slot, in which case we should do so now.
|
||||
if (allocateBuffer)
|
||||
{
|
||||
buffer = new T[_bufferLength];
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to return the buffer to the bucket. If successful, the buffer will be stored
|
||||
/// in the bucket and true will be returned; otherwise, the buffer won't be stored, and false
|
||||
/// will be returned.
|
||||
/// </summary>
|
||||
internal void Return(T[] array)
|
||||
{
|
||||
// Check to see if the buffer is the correct size for this bucket
|
||||
if (array.Length != _bufferLength)
|
||||
{
|
||||
throw new ArgumentException("Buffer not from pool", nameof(array));
|
||||
}
|
||||
|
||||
// While holding the spin lock, if there's room available in the bucket,
|
||||
// put the buffer into the next available slot. Otherwise, we just drop it.
|
||||
// The try/finally is necessary to properly handle thread aborts on platforms
|
||||
// which have them.
|
||||
bool lockTaken = false;
|
||||
try
|
||||
{
|
||||
_lock.Enter(ref lockTaken);
|
||||
|
||||
if (_index != 0)
|
||||
{
|
||||
_buffers[--_index] = array;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken) _lock.Exit(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
38
src/SharpCompress/Buffers/Utilities.cs
Normal file
38
src/SharpCompress/Buffers/Utilities.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
#if NETCORE
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace SharpCompress.Buffers
|
||||
{
|
||||
internal static class Utilities
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int SelectBucketIndex(int bufferSize)
|
||||
{
|
||||
Debug.Assert(bufferSize > 0);
|
||||
|
||||
uint bitsRemaining = ((uint)bufferSize - 1) >> 4;
|
||||
|
||||
int poolIndex = 0;
|
||||
if (bitsRemaining > 0xFFFF) { bitsRemaining >>= 16; poolIndex = 16; }
|
||||
if (bitsRemaining > 0xFF) { bitsRemaining >>= 8; poolIndex += 8; }
|
||||
if (bitsRemaining > 0xF) { bitsRemaining >>= 4; poolIndex += 4; }
|
||||
if (bitsRemaining > 0x3) { bitsRemaining >>= 2; poolIndex += 2; }
|
||||
if (bitsRemaining > 0x1) { bitsRemaining >>= 1; poolIndex += 1; }
|
||||
|
||||
return poolIndex + (int)bitsRemaining;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int GetMaxSizeForBucket(int binIndex)
|
||||
{
|
||||
int maxSize = 16 << binIndex;
|
||||
Debug.Assert(maxSize >= 0);
|
||||
return maxSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,23 +1,60 @@
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public static class ArchiveEncoding
|
||||
public class ArchiveEncoding
|
||||
{
|
||||
/// <summary>
|
||||
/// Default encoding to use when archive format doesn't specify one.
|
||||
/// </summary>
|
||||
public static Encoding Default { get; set; }
|
||||
public Encoding Default { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Encoding used by encryption schemes which don't comply with RFC 2898.
|
||||
/// ArchiveEncoding used by encryption schemes which don't comply with RFC 2898.
|
||||
/// </summary>
|
||||
public static Encoding Password { get; set; }
|
||||
public Encoding Password { get; set; }
|
||||
|
||||
static ArchiveEncoding()
|
||||
/// <summary>
|
||||
/// Set this encoding when you want to force it for all encoding operations.
|
||||
/// </summary>
|
||||
public Encoding Forced { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set this when you want to use a custom method for all decoding operations.
|
||||
/// </summary>
|
||||
/// <returns>string Func(bytes, index, length)</returns>
|
||||
public Func<byte[], int, int, string> CustomDecoder { get; set; }
|
||||
|
||||
public ArchiveEncoding()
|
||||
{
|
||||
Default = Encoding.UTF8;
|
||||
Password = Encoding.UTF8;
|
||||
}
|
||||
|
||||
public string Decode(byte[] bytes)
|
||||
{
|
||||
return Decode(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public string Decode(byte[] bytes, int start, int length)
|
||||
{
|
||||
return GetDecoder().Invoke(bytes, start, length);
|
||||
}
|
||||
|
||||
public byte[] Encode(string str)
|
||||
{
|
||||
return GetEncoding().GetBytes(str);
|
||||
}
|
||||
|
||||
public Encoding GetEncoding()
|
||||
{
|
||||
return Forced ?? Default ?? Encoding.UTF8;
|
||||
}
|
||||
|
||||
public Func<byte[], int, int, string> GetDecoder()
|
||||
{
|
||||
return CustomDecoder ?? ((bytes, index, count) => (Default ?? Encoding.UTF8).GetString(bytes, index, count));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,6 @@ namespace SharpCompress.Common
|
||||
Item = entry;
|
||||
}
|
||||
|
||||
public T Item { get; private set; }
|
||||
public T Item { get; }
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,6 @@
|
||||
Zip,
|
||||
Tar,
|
||||
SevenZip,
|
||||
GZip,
|
||||
GZip
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using SharpCompress.Compressor.Deflate;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Detailed compression properties when saving.
|
||||
/// </summary>
|
||||
public class CompressionInfo
|
||||
{
|
||||
public CompressionInfo()
|
||||
{
|
||||
DeflateCompressionLevel = CompressionLevel.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The algorthm to use. Must be valid for the format type.
|
||||
/// </summary>
|
||||
public CompressionType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default.
|
||||
/// </summary>
|
||||
public CompressionLevel DeflateCompressionLevel { get; set; }
|
||||
|
||||
public static implicit operator CompressionInfo(CompressionType compressionType)
|
||||
{
|
||||
return new CompressionInfo() {Type = compressionType};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,9 @@
|
||||
LZMA,
|
||||
BCJ,
|
||||
BCJ2,
|
||||
LZip,
|
||||
Xz,
|
||||
Unknown,
|
||||
Deflate64
|
||||
}
|
||||
}
|
||||
@@ -65,21 +65,22 @@ namespace SharpCompress.Common
|
||||
/// </summary>
|
||||
public abstract bool IsSplit { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Key;
|
||||
}
|
||||
|
||||
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(); }
|
||||
}
|
||||
|
||||
public virtual int? Attrib => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Reader;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public class EntryStream : Stream
|
||||
{
|
||||
public IReader Reader { get; private set; }
|
||||
private Stream stream;
|
||||
public IReader Reader { get; }
|
||||
private readonly Stream stream;
|
||||
private bool completed;
|
||||
private bool isDisposed;
|
||||
|
||||
internal EntryStream(IReader reader, Stream stream)
|
||||
{
|
||||
this.Reader = reader;
|
||||
Reader = reader;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@@ -44,36 +44,20 @@ namespace SharpCompress.Common
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
|
||||
@@ -4,9 +4,17 @@ namespace SharpCompress.Common
|
||||
{
|
||||
public abstract class FilePart
|
||||
{
|
||||
protected FilePart(ArchiveEncoding archiveEncoding)
|
||||
{
|
||||
ArchiveEncoding = archiveEncoding;
|
||||
}
|
||||
|
||||
internal ArchiveEncoding ArchiveEncoding { get; }
|
||||
|
||||
internal abstract string FilePartName { get; }
|
||||
|
||||
internal abstract Stream GetCompressedStream();
|
||||
internal abstract Stream GetRawStream();
|
||||
internal bool Skipped { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace SharpCompress.Common
|
||||
{
|
||||
return ((bitField & flag) == flag);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the flag is set on the specified bit field.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
@@ -75,7 +75,6 @@ namespace SharpCompress.Common
|
||||
return ((bitField & flag) == flag);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets a bit-field to either on or off for the specified flag.
|
||||
/// </summary>
|
||||
@@ -83,9 +82,9 @@ namespace SharpCompress.Common
|
||||
/// <param name="flag">Flag to change</param>
|
||||
/// <param name="on">bool</param>
|
||||
/// <returns>The flagged variable with the flag changed</returns>
|
||||
public static long SetFlag(long bitField, long flag, bool @on)
|
||||
public static long SetFlag(long bitField, long flag, bool on)
|
||||
{
|
||||
if (@on)
|
||||
if (on)
|
||||
{
|
||||
return bitField | flag;
|
||||
}
|
||||
@@ -100,10 +99,10 @@ namespace SharpCompress.Common
|
||||
/// <param name="flag">Flag to change</param>
|
||||
/// <param name="on">bool</param>
|
||||
/// <returns>The flagged variable with the flag changed</returns>
|
||||
public static long SetFlag<T>(T bitField, T flag, bool @on)
|
||||
public static long SetFlag<T>(T bitField, T flag, bool on)
|
||||
where T : struct
|
||||
{
|
||||
return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), @on);
|
||||
return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), on);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpCompress.Common.GZip
|
||||
{
|
||||
@@ -13,74 +14,35 @@ namespace SharpCompress.Common.GZip
|
||||
this.filePart = filePart;
|
||||
}
|
||||
|
||||
public override CompressionType CompressionType
|
||||
{
|
||||
get { return CompressionType.GZip; }
|
||||
}
|
||||
public override CompressionType CompressionType => CompressionType.GZip;
|
||||
|
||||
public override long Crc
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
public override long Crc => 0;
|
||||
|
||||
public override string Key
|
||||
{
|
||||
get { return filePart.FilePartName; }
|
||||
}
|
||||
public override string Key => filePart.FilePartName;
|
||||
|
||||
public override long CompressedSize
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
public override long CompressedSize => 0;
|
||||
|
||||
public override long Size
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
public override long Size => 0;
|
||||
|
||||
public override DateTime? LastModifiedTime
|
||||
{
|
||||
get { return filePart.DateModified; }
|
||||
}
|
||||
public override DateTime? LastModifiedTime => filePart.DateModified;
|
||||
|
||||
public override DateTime? CreatedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
public override DateTime? CreatedTime => null;
|
||||
|
||||
public override DateTime? LastAccessedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
public override DateTime? LastAccessedTime => null;
|
||||
|
||||
public override DateTime? ArchivedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
public override DateTime? ArchivedTime => null;
|
||||
|
||||
public override bool IsEncrypted
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool IsEncrypted => false;
|
||||
|
||||
public override bool IsDirectory
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool IsDirectory => false;
|
||||
|
||||
public override bool IsSplit
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool IsSplit => false;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts
|
||||
{
|
||||
get { return filePart.AsEnumerable<FilePart>(); }
|
||||
}
|
||||
internal override IEnumerable<FilePart> Parts => filePart.AsEnumerable<FilePart>();
|
||||
|
||||
internal static IEnumerable<GZipEntry> GetEntries(Stream stream)
|
||||
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, OptionsBase options)
|
||||
{
|
||||
yield return new GZipEntry(new GZipFilePart(stream));
|
||||
yield return new GZipEntry(new GZipFilePart(stream, options.ArchiveEncoding));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Compressor;
|
||||
using SharpCompress.Compressor.Deflate;
|
||||
using SharpCompress.Converter;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Converters;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpCompress.Common.GZip
|
||||
{
|
||||
internal class GZipFilePart : FilePart
|
||||
{
|
||||
private string name;
|
||||
private readonly Stream stream;
|
||||
private string _name;
|
||||
private readonly Stream _stream;
|
||||
|
||||
internal GZipFilePart(Stream stream)
|
||||
internal GZipFilePart(Stream stream, ArchiveEncoding archiveEncoding)
|
||||
: base(archiveEncoding)
|
||||
{
|
||||
ReadAndValidateGzipHeader(stream);
|
||||
this.stream = stream;
|
||||
EntryStartPosition = stream.Position;
|
||||
this._stream = stream;
|
||||
}
|
||||
|
||||
internal long EntryStartPosition { get; }
|
||||
|
||||
internal DateTime? DateModified { get; private set; }
|
||||
|
||||
internal override string FilePartName
|
||||
{
|
||||
get { return name; }
|
||||
}
|
||||
internal override string FilePartName => _name;
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
return new DeflateStream(stream, CompressionMode.Decompress, CompressionLevel.Default, false);
|
||||
return new DeflateStream(_stream, CompressionMode.Decompress, CompressionLevel.Default, false);
|
||||
}
|
||||
|
||||
internal override Stream GetRawStream()
|
||||
{
|
||||
return stream;
|
||||
return _stream;
|
||||
}
|
||||
|
||||
private void ReadAndValidateGzipHeader(Stream stream)
|
||||
@@ -43,13 +46,19 @@ namespace SharpCompress.Common.GZip
|
||||
|
||||
// workitem 8501: handle edge case (decompress empty stream)
|
||||
if (n == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (n != 10)
|
||||
{
|
||||
throw new ZlibException("Not a valid GZIP stream.");
|
||||
}
|
||||
|
||||
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
|
||||
{
|
||||
throw new ZlibException("Bad GZIP header.");
|
||||
}
|
||||
|
||||
Int32 timet = DataConverter.LittleEndian.GetInt32(header, 4);
|
||||
DateModified = TarHeader.Epoch.AddSeconds(timet);
|
||||
@@ -58,27 +67,33 @@ namespace SharpCompress.Common.GZip
|
||||
// read and discard extra field
|
||||
n = stream.Read(header, 0, 2); // 2-byte length field
|
||||
|
||||
Int16 extraLength = (Int16) (header[0] + header[1]*256);
|
||||
Int16 extraLength = (Int16)(header[0] + header[1] * 256);
|
||||
byte[] extra = new byte[extraLength];
|
||||
n = stream.Read(extra, 0, extra.Length);
|
||||
if (n != extraLength)
|
||||
|
||||
if (!stream.ReadFully(extra))
|
||||
{
|
||||
throw new ZlibException("Unexpected end-of-file reading GZIP header.");
|
||||
}
|
||||
n = extraLength;
|
||||
}
|
||||
if ((header[3] & 0x08) == 0x08)
|
||||
name = ReadZeroTerminatedString(stream);
|
||||
{
|
||||
_name = ReadZeroTerminatedString(stream);
|
||||
}
|
||||
if ((header[3] & 0x10) == 0x010)
|
||||
{
|
||||
ReadZeroTerminatedString(stream);
|
||||
}
|
||||
if ((header[3] & 0x02) == 0x02)
|
||||
{
|
||||
stream.ReadByte(); // CRC16, ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static string ReadZeroTerminatedString(Stream stream)
|
||||
private string ReadZeroTerminatedString(Stream stream)
|
||||
{
|
||||
byte[] buf1 = new byte[1];
|
||||
var list = new System.Collections.Generic.List<byte>();
|
||||
var list = new List<byte>();
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
@@ -96,9 +111,10 @@ namespace SharpCompress.Common.GZip
|
||||
{
|
||||
list.Add(buf1[0]);
|
||||
}
|
||||
} while (!done);
|
||||
byte[] a = list.ToArray();
|
||||
return ArchiveEncoding.Default.GetString(a, 0, a.Length);
|
||||
}
|
||||
while (!done);
|
||||
byte[] buffer = list.ToArray();
|
||||
return ArchiveEncoding.Decode(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,25 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.GZip
|
||||
{
|
||||
public class GZipVolume : Volume
|
||||
{
|
||||
public GZipVolume(Stream stream, Options options)
|
||||
public GZipVolume(Stream stream, ReaderOptions options)
|
||||
: base(stream, options)
|
||||
{
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
public GZipVolume(FileInfo fileInfo, Options options)
|
||||
public GZipVolume(FileInfo fileInfo, ReaderOptions options)
|
||||
: base(fileInfo.OpenRead(), options)
|
||||
{
|
||||
options.LeaveStreamOpen = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
public override bool IsFirstVolume
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public override bool IsFirstVolume => true;
|
||||
|
||||
public override bool IsMultiVolume
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public override bool IsMultiVolume => true;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
#if !NO_FILE
|
||||
|
||||
#if !NO_FILE
|
||||
using System.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
internal static class IEntryExtensions
|
||||
{
|
||||
internal static void PreserveExtractionOptions(this IEntry entry, string destinationFileName,
|
||||
ExtractOptions options)
|
||||
ExtractionOptions options)
|
||||
{
|
||||
if (options.HasFlag(ExtractOptions.PreserveFileTime) || options.HasFlag(ExtractOptions.PreserveAttributes))
|
||||
if (options.PreserveFileTime || options.PreserveAttributes)
|
||||
{
|
||||
FileInfo nf = new FileInfo(destinationFileName);
|
||||
if (!nf.Exists)
|
||||
@@ -17,7 +19,7 @@ namespace SharpCompress.Common
|
||||
}
|
||||
|
||||
// update file time to original packed time
|
||||
if (options.HasFlag(ExtractOptions.PreserveFileTime))
|
||||
if (options.PreserveFileTime)
|
||||
{
|
||||
if (entry.CreatedTime.HasValue)
|
||||
{
|
||||
@@ -35,7 +37,7 @@ namespace SharpCompress.Common
|
||||
}
|
||||
}
|
||||
|
||||
if (options.HasFlag(ExtractOptions.PreserveAttributes))
|
||||
if (options.PreserveAttributes)
|
||||
{
|
||||
if (entry.Attrib.HasValue)
|
||||
{
|
||||
@@ -46,4 +48,4 @@ namespace SharpCompress.Common
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
|
||||
#if !NO_FILE
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
[Flags]
|
||||
public enum Options
|
||||
{
|
||||
/// <summary>
|
||||
/// No options specified
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// SharpCompress will keep the supplied streams open
|
||||
/// </summary>
|
||||
KeepStreamsOpen = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file)
|
||||
/// </summary>
|
||||
LookForHeader = 2,
|
||||
}
|
||||
}
|
||||
13
src/SharpCompress/Common/OptionsBase.cs
Normal file
13
src/SharpCompress/Common/OptionsBase.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public class OptionsBase
|
||||
{
|
||||
/// <summary>
|
||||
/// SharpCompress will keep the supplied streams open. Default is true.
|
||||
/// </summary>
|
||||
public bool LeaveStreamOpen { get; set; } = true;
|
||||
|
||||
public ArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding();
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
}
|
||||
|
||||
internal ArchiveFlags ArchiveHeaderFlags
|
||||
{
|
||||
get { return (ArchiveFlags) base.Flags; }
|
||||
}
|
||||
internal ArchiveFlags ArchiveHeaderFlags => (ArchiveFlags)Flags;
|
||||
|
||||
internal short HighPosAv { get; private set; }
|
||||
|
||||
@@ -28,9 +25,6 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
internal byte EncryptionVersion { get; private set; }
|
||||
|
||||
public bool HasPassword
|
||||
{
|
||||
get { return ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD); }
|
||||
}
|
||||
public bool HasPassword => ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD);
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
}
|
||||
|
||||
internal EndArchiveFlags EndArchiveFlags
|
||||
{
|
||||
get { return (EndArchiveFlags) base.Flags; }
|
||||
}
|
||||
internal EndArchiveFlags EndArchiveFlags => (EndArchiveFlags)Flags;
|
||||
|
||||
internal int? ArchiveCRC { get; private set; }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using SharpCompress.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
@@ -68,12 +68,12 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
else
|
||||
{
|
||||
FileName = DecodeDefault(fileNameBytes);
|
||||
FileName = ArchiveEncoding.Decode(fileNameBytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FileName = DecodeDefault(fileNameBytes);
|
||||
FileName = ArchiveEncoding.Decode(fileNameBytes);
|
||||
}
|
||||
FileName = ConvertPath(FileName, HostOS);
|
||||
}
|
||||
@@ -118,12 +118,6 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
}
|
||||
|
||||
//only the full .net framework will do other code pages than unicode/utf8
|
||||
private string DecodeDefault(byte[] bytes)
|
||||
{
|
||||
return ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
private long UInt32To64(uint x, uint y)
|
||||
{
|
||||
long l = x;
|
||||
@@ -155,6 +149,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
byte b = reader.ReadByte();
|
||||
nanosecondHundreds |= (((uint)b) << ((j + 3 - count) * 8));
|
||||
}
|
||||
|
||||
//10^-7 to 10^-3
|
||||
return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4));
|
||||
}
|
||||
@@ -164,31 +159,20 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
#if NO_FILE
|
||||
return path.Replace('\\', '/');
|
||||
#else
|
||||
switch (os)
|
||||
if (Path.DirectorySeparatorChar == '/')
|
||||
{
|
||||
case HostOS.MacOS:
|
||||
case HostOS.Unix:
|
||||
{
|
||||
if (Path.DirectorySeparatorChar == '\\')
|
||||
{
|
||||
return path.Replace('/', '\\');
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if (Path.DirectorySeparatorChar == '/')
|
||||
{
|
||||
return path.Replace('\\', '/');
|
||||
}
|
||||
}
|
||||
break;
|
||||
return path.Replace('\\', '/');
|
||||
}
|
||||
else if (Path.DirectorySeparatorChar == '\\')
|
||||
{
|
||||
return path.Replace('/', '\\');
|
||||
}
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal long DataStartPosition { get; set; }
|
||||
|
||||
internal HostOS HostOS { get; private set; }
|
||||
|
||||
internal uint FileCRC { get; private set; }
|
||||
@@ -207,12 +191,10 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
internal int FileAttributes { get; private set; }
|
||||
|
||||
internal FileFlags FileFlags
|
||||
{
|
||||
get { return (FileFlags)base.Flags; }
|
||||
}
|
||||
internal FileFlags FileFlags => (FileFlags)Flags;
|
||||
|
||||
internal long CompressedSize { get; private set; }
|
||||
|
||||
internal long UncompressedSize { get; private set; }
|
||||
|
||||
internal string FileName { get; private set; }
|
||||
|
||||
@@ -32,19 +32,19 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
switch (flags >> 6)
|
||||
{
|
||||
case 0:
|
||||
buf.Append((char) (GetChar(name, encPos++)));
|
||||
buf.Append((char)(GetChar(name, encPos++)));
|
||||
++decPos;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buf.Append((char) (GetChar(name, encPos++) + (highByte << 8)));
|
||||
buf.Append((char)(GetChar(name, encPos++) + (highByte << 8)));
|
||||
++decPos;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
low = GetChar(name, encPos);
|
||||
high = GetChar(name, encPos + 1);
|
||||
buf.Append((char) ((high << 8) + low));
|
||||
buf.Append((char)((high << 8) + low));
|
||||
++decPos;
|
||||
encPos += 2;
|
||||
break;
|
||||
@@ -57,14 +57,14 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
for (length = (length & 0x7f) + 2; length > 0 && decPos < name.Length; length--, decPos++)
|
||||
{
|
||||
low = (GetChar(name, decPos) + correction) & 0xff;
|
||||
buf.Append((char) ((highByte << 8) + low));
|
||||
buf.Append((char)((highByte << 8) + low));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (length += 2; length > 0 && decPos < name.Length; length--, decPos++)
|
||||
{
|
||||
buf.Append((char) (GetChar(name, decPos)));
|
||||
buf.Append((char)(GetChar(name, decPos)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -13,12 +13,12 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
ProtectHeader = 0x78,
|
||||
SignHeader = 0x79,
|
||||
NewSubHeader = 0x7a,
|
||||
EndArchiveHeader = 0x7b,
|
||||
EndArchiveHeader = 0x7b
|
||||
}
|
||||
|
||||
internal enum HeaderFlags : short
|
||||
{
|
||||
LONG_BLOCK = -0x8000,
|
||||
LONG_BLOCK = -0x8000
|
||||
}
|
||||
|
||||
[Flags]
|
||||
@@ -33,7 +33,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
PROTECT = 0x0040,
|
||||
PASSWORD = 0x0080,
|
||||
FIRSTVOLUME = 0x0100,
|
||||
ENCRYPTVER = 0x0200,
|
||||
ENCRYPTVER = 0x0200
|
||||
}
|
||||
|
||||
internal enum HostOS
|
||||
@@ -70,16 +70,15 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
SALT = 0x0400,
|
||||
VERSION = 0x0800,
|
||||
EXTTIME = 0x1000,
|
||||
EXTFLAGS = 0x2000,
|
||||
EXTFLAGS = 0x2000
|
||||
}
|
||||
|
||||
|
||||
[Flags]
|
||||
internal enum EndArchiveFlags
|
||||
{
|
||||
EARC_NEXT_VOLUME = 0x0001,
|
||||
EARC_DATACRC = 0x0002,
|
||||
EARC_REVSPACE = 0x0004,
|
||||
EARC_VOLNUMBER = 0x0008,
|
||||
EARC_VOLNUMBER = 0x0008
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,9 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
Flags == 0x1A21 &&
|
||||
HeaderSize == 0x07;
|
||||
|
||||
// Rar5 signature: 52 61 72 21 1A 07 10 00 (not supported yet)
|
||||
// Rar5 signature: 52 61 72 21 1A 07 01 00 (not supported yet)
|
||||
}
|
||||
|
||||
internal bool OldFormat { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,14 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
//internal static final NewSubHeaderType SUBHEAD_TYPE_BEOSEA = new NewSubHeaderType(new byte[]{'E','A','B','E'});
|
||||
|
||||
private byte[] bytes;
|
||||
private readonly byte[] bytes;
|
||||
|
||||
private NewSubHeaderType(params char[] chars)
|
||||
{
|
||||
bytes = new byte[chars.Length];
|
||||
for (int i = 0; i < chars.Length; ++i)
|
||||
{
|
||||
bytes[i] = (byte) chars[i];
|
||||
bytes[i] = (byte)chars[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
Mark = reader.ReadBytes(8);
|
||||
}
|
||||
|
||||
internal uint DataSize { get { return AdditionalSize; } }
|
||||
internal uint DataSize => 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
@@ -16,16 +18,18 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
HeaderSize = baseHeader.HeaderSize;
|
||||
AdditionalSize = baseHeader.AdditionalSize;
|
||||
ReadBytes = baseHeader.ReadBytes;
|
||||
ArchiveEncoding = baseHeader.ArchiveEncoding;
|
||||
}
|
||||
|
||||
internal static RarHeader Create(MarkingBinaryReader reader)
|
||||
internal static RarHeader Create(RarCrcBinaryReader reader, ArchiveEncoding archiveEncoding)
|
||||
{
|
||||
try
|
||||
{
|
||||
RarHeader header = new RarHeader();
|
||||
|
||||
header.ArchiveEncoding = archiveEncoding;
|
||||
reader.Mark();
|
||||
header.ReadFromReader(reader);
|
||||
header.ReadStartFromReader(reader);
|
||||
header.ReadBytes += reader.CurrentReadByteCount;
|
||||
|
||||
return header;
|
||||
@@ -35,9 +39,11 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
return null;
|
||||
}
|
||||
}
|
||||
protected virtual void ReadFromReader(MarkingBinaryReader reader)
|
||||
|
||||
private void ReadStartFromReader(RarCrcBinaryReader reader)
|
||||
{
|
||||
HeadCRC = reader.ReadInt16();
|
||||
HeadCRC = reader.ReadUInt16();
|
||||
reader.ResetCrc();
|
||||
HeaderType = (HeaderType)(reader.ReadByte() & 0xff);
|
||||
Flags = reader.ReadInt16();
|
||||
HeaderSize = reader.ReadInt16();
|
||||
@@ -47,7 +53,12 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
}
|
||||
|
||||
internal T PromoteHeader<T>(MarkingBinaryReader reader)
|
||||
protected virtual void ReadFromReader(MarkingBinaryReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal T PromoteHeader<T>(RarCrcBinaryReader reader)
|
||||
where T : RarHeader, new()
|
||||
{
|
||||
T header = new T();
|
||||
@@ -64,9 +75,22 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
reader.ReadBytes(headerSizeDiff);
|
||||
}
|
||||
|
||||
VerifyHeaderCrc(reader.GetCrc());
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private void VerifyHeaderCrc(ushort crc)
|
||||
{
|
||||
if (HeaderType != HeaderType.MarkHeader)
|
||||
{
|
||||
if (crc != HeadCRC)
|
||||
{
|
||||
throw new InvalidFormatException("rar header crc mismatch");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void PostReadingBytes(MarkingBinaryReader reader)
|
||||
{
|
||||
}
|
||||
@@ -76,7 +100,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
/// </summary>
|
||||
protected long ReadBytes { get; private set; }
|
||||
|
||||
protected short HeadCRC { get; private set; }
|
||||
protected ushort HeadCRC { get; private set; }
|
||||
|
||||
internal HeaderType HeaderType { get; private set; }
|
||||
|
||||
@@ -87,6 +111,8 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
protected short HeaderSize { get; private set; }
|
||||
|
||||
internal ArchiveEncoding ArchiveEncoding { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This additional size of the header could be file data
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
@@ -9,21 +10,19 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
private const int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136
|
||||
|
||||
internal RarHeaderFactory(StreamingMode mode, Options options, string password = null)
|
||||
internal RarHeaderFactory(StreamingMode mode, ReaderOptions options)
|
||||
{
|
||||
StreamingMode = mode;
|
||||
Options = options;
|
||||
Password = password;
|
||||
}
|
||||
|
||||
private Options Options { get; set; }
|
||||
public string Password { get; private set; }
|
||||
internal StreamingMode StreamingMode { get; private set; }
|
||||
private ReaderOptions Options { get; }
|
||||
internal StreamingMode StreamingMode { get; }
|
||||
internal bool IsEncrypted { get; private set; }
|
||||
|
||||
|
||||
internal IEnumerable<RarHeader> ReadHeaders(Stream stream)
|
||||
{
|
||||
if (Options.HasFlag(Options.LookForHeader))
|
||||
if (Options.LookForHeader)
|
||||
{
|
||||
stream = CheckSFX(stream);
|
||||
}
|
||||
@@ -91,7 +90,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!Options.HasFlag(Options.KeepStreamsOpen))
|
||||
if (!Options.LeaveStreamOpen)
|
||||
{
|
||||
#if NET35
|
||||
reader.Close();
|
||||
@@ -114,15 +113,14 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
return rewindableStream;
|
||||
}
|
||||
|
||||
|
||||
private RarHeader ReadNextHeader(Stream stream)
|
||||
{
|
||||
#if !NO_CRYPTO
|
||||
var reader = new RarCryptoBinaryReader(stream, Password);
|
||||
|
||||
var reader = new RarCryptoBinaryReader(stream, Options.Password);
|
||||
|
||||
if (IsEncrypted)
|
||||
{
|
||||
if (Password == null)
|
||||
if (Options.Password == null)
|
||||
{
|
||||
throw new CryptographicException("Encrypted Rar archive has no password specified.");
|
||||
}
|
||||
@@ -131,11 +129,11 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
reader.InitializeAes(salt);
|
||||
}
|
||||
#else
|
||||
var reader = new MarkingBinaryReader(stream);
|
||||
var reader = new RarCrcBinaryReader(stream);
|
||||
|
||||
#endif
|
||||
|
||||
RarHeader header = RarHeader.Create(reader);
|
||||
RarHeader header = RarHeader.Create(reader, Options.ArchiveEncoding);
|
||||
if (header == null)
|
||||
{
|
||||
return null;
|
||||
@@ -156,7 +154,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
case HeaderType.ProtectHeader:
|
||||
{
|
||||
ProtectHeader ph = header.PromoteHeader<ProtectHeader>(reader);
|
||||
|
||||
|
||||
// skip the recovery record data, we do not use it.
|
||||
switch (StreamingMode)
|
||||
{
|
||||
@@ -224,9 +222,9 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
else
|
||||
{
|
||||
#if !NO_CRYPTO
|
||||
fh.PackedStream = new RarCryptoWrapper(ms, Password, fh.Salt);
|
||||
fh.PackedStream = new RarCryptoWrapper(ms, Options.Password, fh.Salt);
|
||||
#else
|
||||
throw new NotSupportedException("RarCrypto not supported");
|
||||
throw new NotSupportedException("RarCrypto not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -244,7 +242,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new InvalidFormatException("Invalid Rar Header: " + header.HeaderType.ToString());
|
||||
throw new InvalidFormatException("Invalid Rar Header: " + header.HeaderType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
40
src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs
Normal file
40
src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Compressors.Rar;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Rar {
|
||||
internal class RarCrcBinaryReader : MarkingBinaryReader {
|
||||
private uint currentCrc;
|
||||
|
||||
public RarCrcBinaryReader(Stream stream) : base(stream)
|
||||
{
|
||||
}
|
||||
|
||||
public ushort GetCrc()
|
||||
{
|
||||
return (ushort)~currentCrc;
|
||||
}
|
||||
|
||||
public void ResetCrc()
|
||||
{
|
||||
currentCrc = 0xffffffff;
|
||||
}
|
||||
|
||||
protected void UpdateCrc(byte b)
|
||||
{
|
||||
currentCrc = RarCRC.CheckCrc(currentCrc, b);
|
||||
}
|
||||
|
||||
protected byte[] ReadBytesNoCrc(int count)
|
||||
{
|
||||
return base.ReadBytes(count);
|
||||
}
|
||||
|
||||
public override byte[] ReadBytes(int count)
|
||||
{
|
||||
var result = base.ReadBytes(count);
|
||||
currentCrc = RarCRC.CheckCrc(currentCrc, result, 0, result.Length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,18 @@
|
||||
#if !NO_CRYPTO
|
||||
|
||||
#if !NO_CRYPTO
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Rar
|
||||
{
|
||||
internal class RarCryptoBinaryReader : MarkingBinaryReader
|
||||
internal class RarCryptoBinaryReader : RarCrcBinaryReader
|
||||
{
|
||||
private RarRijndael rijndael;
|
||||
private byte[] salt;
|
||||
private readonly string password;
|
||||
private readonly Queue<byte> data = new Queue<byte>();
|
||||
private long readCount;
|
||||
|
||||
public RarCryptoBinaryReader(Stream stream, string password )
|
||||
: base(stream)
|
||||
@@ -18,6 +20,22 @@ namespace SharpCompress.Common.Rar
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
// track read count ourselves rather than using the underlying stream since we buffer
|
||||
public override long CurrentReadByteCount {
|
||||
get
|
||||
{
|
||||
return this.readCount;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
public override void Mark() {
|
||||
this.readCount = 0;
|
||||
}
|
||||
|
||||
protected bool UseEncryption
|
||||
{
|
||||
get { return salt != null; }
|
||||
@@ -35,6 +53,7 @@ namespace SharpCompress.Common.Rar
|
||||
{
|
||||
return ReadAndDecryptBytes(count);
|
||||
}
|
||||
this.readCount += count;
|
||||
return base.ReadBytes(count);
|
||||
}
|
||||
|
||||
@@ -49,7 +68,7 @@ namespace SharpCompress.Common.Rar
|
||||
for (int i = 0; i < alignedSize / 16; i++)
|
||||
{
|
||||
//long ax = System.currentTimeMillis();
|
||||
byte[] cipherText = base.ReadBytes(16);
|
||||
byte[] cipherText = base.ReadBytesNoCrc(16);
|
||||
var readBytes = rijndael.ProcessBlock(cipherText);
|
||||
foreach (var readByte in readBytes)
|
||||
data.Enqueue(readByte);
|
||||
@@ -62,8 +81,11 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
decryptedBytes[i] = data.Dequeue();
|
||||
var b = data.Dequeue();
|
||||
decryptedBytes[i] = b;
|
||||
UpdateCrc(b);
|
||||
}
|
||||
this.readCount += count;
|
||||
return decryptedBytes;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
#if !NO_CRYPTO
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -10,71 +10,44 @@ namespace SharpCompress.Common.Rar
|
||||
/// <summary>
|
||||
/// The File's 32 bit CRC Hash
|
||||
/// </summary>
|
||||
public override long Crc
|
||||
{
|
||||
get { return FileHeader.FileCRC; }
|
||||
}
|
||||
public override long Crc => FileHeader.FileCRC;
|
||||
|
||||
/// <summary>
|
||||
/// The path of the file internal to the Rar Archive.
|
||||
/// </summary>
|
||||
public override string Key
|
||||
{
|
||||
get { return FileHeader.FileName; }
|
||||
}
|
||||
public override string Key => FileHeader.FileName;
|
||||
|
||||
/// <summary>
|
||||
/// The entry last modified time in the archive, if recorded
|
||||
/// </summary>
|
||||
public override DateTime? LastModifiedTime
|
||||
{
|
||||
get { return FileHeader.FileLastModifiedTime; }
|
||||
}
|
||||
public override DateTime? LastModifiedTime => FileHeader.FileLastModifiedTime;
|
||||
|
||||
/// <summary>
|
||||
/// The entry create time in the archive, if recorded
|
||||
/// </summary>
|
||||
public override DateTime? CreatedTime
|
||||
{
|
||||
get { return FileHeader.FileCreatedTime; }
|
||||
}
|
||||
public override DateTime? CreatedTime => FileHeader.FileCreatedTime;
|
||||
|
||||
/// <summary>
|
||||
/// The entry last accessed time in the archive, if recorded
|
||||
/// </summary>
|
||||
public override DateTime? LastAccessedTime
|
||||
{
|
||||
get { return FileHeader.FileLastAccessedTime; }
|
||||
}
|
||||
public override DateTime? LastAccessedTime => FileHeader.FileLastAccessedTime;
|
||||
|
||||
/// <summary>
|
||||
/// The entry time whend archived, if recorded
|
||||
/// </summary>
|
||||
public override DateTime? ArchivedTime
|
||||
{
|
||||
get { return FileHeader.FileArchivedTime; }
|
||||
}
|
||||
public override DateTime? ArchivedTime => FileHeader.FileArchivedTime;
|
||||
|
||||
/// <summary>
|
||||
/// Entry is password protected and encrypted and cannot be extracted.
|
||||
/// </summary>
|
||||
public override bool IsEncrypted
|
||||
{
|
||||
get { return FileHeader.FileFlags.HasFlag(FileFlags.PASSWORD); }
|
||||
}
|
||||
public override bool IsEncrypted => FileHeader.FileFlags.HasFlag(FileFlags.PASSWORD);
|
||||
|
||||
/// <summary>
|
||||
/// Entry is password protected and encrypted and cannot be extracted.
|
||||
/// </summary>
|
||||
public override bool IsDirectory
|
||||
{
|
||||
get { return FileHeader.FileFlags.HasFlag(FileFlags.DIRECTORY); }
|
||||
}
|
||||
public override bool IsDirectory => FileHeader.FileFlags.HasFlag(FileFlags.DIRECTORY);
|
||||
|
||||
public override bool IsSplit
|
||||
{
|
||||
get { return FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER); }
|
||||
}
|
||||
public override bool IsSplit => FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -9,14 +9,15 @@ namespace SharpCompress.Common.Rar
|
||||
internal abstract class RarFilePart : FilePart
|
||||
{
|
||||
internal RarFilePart(MarkHeader mh, FileHeader fh)
|
||||
: base(fh.ArchiveEncoding)
|
||||
{
|
||||
MarkHeader = mh;
|
||||
FileHeader = fh;
|
||||
}
|
||||
|
||||
internal MarkHeader MarkHeader { get; private set; }
|
||||
internal MarkHeader MarkHeader { get; }
|
||||
|
||||
internal FileHeader FileHeader { get; private set; }
|
||||
internal FileHeader FileHeader { get; }
|
||||
|
||||
internal override Stream GetRawStream()
|
||||
{
|
||||
|
||||
@@ -74,13 +74,16 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
byte[] aesKey = new byte[CRYPTO_BLOCK_SIZE];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
aesKey[i*4 + j] = (byte)
|
||||
(((digest[i*4]*0x1000000) & 0xff000000 |
|
||||
(uint) ((digest[i*4 + 1]*0x10000) & 0xff0000) |
|
||||
(uint) ((digest[i*4 + 2]*0x100) & 0xff00) |
|
||||
(uint) (digest[i*4 + 3] & 0xff)) >> (j*8));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
rijndael.Init(false, new KeyParameter(aesKey));
|
||||
|
||||
@@ -100,10 +103,14 @@ namespace SharpCompress.Common.Rar
|
||||
rijndael.ProcessBlock(cipherText, 0, plainText, 0);
|
||||
|
||||
for (int j = 0; j < plainText.Length; j++)
|
||||
{
|
||||
decryptedBytes.Add((byte) (plainText[j] ^ aesInitializationVector[j%16])); //32:114, 33:101
|
||||
}
|
||||
|
||||
for (int j = 0; j < aesInitializationVector.Length; j++)
|
||||
{
|
||||
aesInitializationVector[j] = cipherText[j];
|
||||
}
|
||||
return decryptedBytes.ToArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.Rar
|
||||
{
|
||||
@@ -13,20 +14,14 @@ namespace SharpCompress.Common.Rar
|
||||
public abstract class RarVolume : Volume
|
||||
{
|
||||
private readonly RarHeaderFactory headerFactory;
|
||||
|
||||
internal RarVolume(StreamingMode mode, Stream stream, string password, Options options)
|
||||
|
||||
internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options)
|
||||
: base(stream, options)
|
||||
{
|
||||
headerFactory = new RarHeaderFactory(mode, options, password);
|
||||
Password = password;
|
||||
headerFactory = new RarHeaderFactory(mode, options);
|
||||
}
|
||||
|
||||
internal string Password { get; private set; }
|
||||
|
||||
internal StreamingMode Mode
|
||||
{
|
||||
get { return headerFactory.StreamingMode; }
|
||||
}
|
||||
internal StreamingMode Mode => headerFactory.StreamingMode;
|
||||
|
||||
internal abstract IEnumerable<RarFilePart> ReadFileParts();
|
||||
|
||||
@@ -35,26 +30,26 @@ namespace SharpCompress.Common.Rar
|
||||
internal IEnumerable<RarFilePart> GetVolumeFileParts()
|
||||
{
|
||||
MarkHeader previousMarkHeader = null;
|
||||
foreach (RarHeader header in headerFactory.ReadHeaders(this.Stream))
|
||||
foreach (RarHeader header in headerFactory.ReadHeaders(Stream))
|
||||
{
|
||||
switch (header.HeaderType)
|
||||
{
|
||||
case HeaderType.ArchiveHeader:
|
||||
{
|
||||
ArchiveHeader = header as ArchiveHeader;
|
||||
}
|
||||
{
|
||||
ArchiveHeader = header as ArchiveHeader;
|
||||
}
|
||||
break;
|
||||
case HeaderType.MarkHeader:
|
||||
{
|
||||
previousMarkHeader = header as MarkHeader;
|
||||
}
|
||||
{
|
||||
previousMarkHeader = header as MarkHeader;
|
||||
}
|
||||
break;
|
||||
case HeaderType.FileHeader:
|
||||
{
|
||||
FileHeader fh = header as FileHeader;
|
||||
RarFilePart fp = CreateFilePart(fh, previousMarkHeader);
|
||||
yield return fp;
|
||||
}
|
||||
{
|
||||
FileHeader fh = header as FileHeader;
|
||||
RarFilePart fp = CreateFilePart(fh, previousMarkHeader);
|
||||
yield return fp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -70,6 +65,7 @@ namespace SharpCompress.Common.Rar
|
||||
{
|
||||
throw new InvalidOperationException("ArchiveHeader should never been null in a streaming read.");
|
||||
}
|
||||
|
||||
//we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream
|
||||
GetVolumeFileParts().First();
|
||||
Stream.Position = 0;
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
using System;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public class ReaderExtractionEventArgs<T> : EventArgs
|
||||
{
|
||||
internal ReaderExtractionEventArgs(T entry)
|
||||
internal ReaderExtractionEventArgs(T entry, ReaderProgress readerProgress = null)
|
||||
{
|
||||
Item = entry;
|
||||
ReaderProgress = readerProgress;
|
||||
}
|
||||
public T Item { get; private set; }
|
||||
|
||||
public T Item { get; }
|
||||
public ReaderProgress ReaderProgress { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Compressor.LZMA;
|
||||
using SharpCompress.Compressor.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
@@ -22,6 +22,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
internal List<long> PackStreamStartPositions = new List<long>();
|
||||
internal List<int> FolderStartFileIndex = new List<int>();
|
||||
internal List<int> FileIndexToFolderIndexMap = new List<int>();
|
||||
|
||||
internal IPasswordProvider PasswordProvider { get; }
|
||||
|
||||
public ArchiveDatabase(IPasswordProvider passwordProvider)
|
||||
{
|
||||
PasswordProvider = passwordProvider;
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
@@ -80,15 +87,19 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
// v3.13 incorrectly worked with empty folders
|
||||
// v4.07: Loop for skipping empty folders
|
||||
for (; ; )
|
||||
for (;;)
|
||||
{
|
||||
if (folderIndex >= Folders.Count)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
FolderStartFileIndex.Add(i); // check it
|
||||
|
||||
if (NumUnpackStreamsVector[folderIndex] != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
folderIndex++;
|
||||
}
|
||||
@@ -97,7 +108,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
FileIndexToFolderIndexMap.Add(folderIndex);
|
||||
|
||||
if (emptyStream)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
indexInFolder++;
|
||||
|
||||
@@ -128,7 +141,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
long size = 0;
|
||||
for (int i = 0; i < folder.PackStreams.Count; i++)
|
||||
{
|
||||
size += PackSizes[packStreamIndex + i];
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -139,7 +154,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
long folderStartPackPos = GetFolderStreamPos(folder, 0);
|
||||
List<long> packSizes = new List<long>();
|
||||
for (int j = 0; j < folder.PackStreams.Count; j++)
|
||||
{
|
||||
packSizes.Add(PackSizes[packStreamIndex + j]);
|
||||
}
|
||||
|
||||
return DecoderStreamHelper.CreateDecoderStream(stream, folderStartPackPos, packSizes.ToArray(), folder, pw);
|
||||
}
|
||||
@@ -153,8 +170,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
int folderIndex = FileIndexToFolderIndexMap[fileIndex];
|
||||
if (folderIndex != -1)
|
||||
{
|
||||
if (FolderStartFileIndex[folderIndex] == fileIndex)
|
||||
{
|
||||
return GetFolderFullPackSize(folderIndex);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Compressor.LZMA;
|
||||
using SharpCompress.Compressor.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip
|
||||
@@ -17,7 +18,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
internal long _streamEnding;
|
||||
internal byte[] _header;
|
||||
|
||||
private Dictionary<int, Stream> _cachedStreams = new Dictionary<int, Stream>();
|
||||
private readonly Dictionary<int, Stream> _cachedStreams = new Dictionary<int, Stream>();
|
||||
|
||||
internal void AddByteStream(byte[] buffer, int offset, int length)
|
||||
{
|
||||
@@ -66,7 +67,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
ulong id = _currentReader.ReadNumber();
|
||||
if (id > 25)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine("ReadId: {0}", (BlockType)id);
|
||||
#endif
|
||||
@@ -85,13 +88,17 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
private void WaitAttribute(BlockType attribute)
|
||||
{
|
||||
for (; ; )
|
||||
for (;;)
|
||||
{
|
||||
BlockType? type = ReadId();
|
||||
if (type == attribute)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (type == BlockType.End)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
SkipData();
|
||||
}
|
||||
}
|
||||
@@ -99,7 +106,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
private void ReadArchiveProperties()
|
||||
{
|
||||
while (ReadId() != BlockType.End)
|
||||
{
|
||||
SkipData();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -122,7 +131,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
|
||||
if ((data & mask) != 0)
|
||||
{
|
||||
bits.SetBit(i);
|
||||
}
|
||||
|
||||
mask >>= 1;
|
||||
}
|
||||
@@ -134,7 +145,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
byte allTrue = ReadByte();
|
||||
if (allTrue != 0)
|
||||
{
|
||||
return new BitVector(length, true);
|
||||
}
|
||||
|
||||
return ReadBitVector(length);
|
||||
}
|
||||
@@ -150,9 +163,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
{
|
||||
if (defined[i])
|
||||
{
|
||||
action(i, checked((long)ReadUInt64()));
|
||||
}
|
||||
else
|
||||
{
|
||||
action(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,10 +182,11 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
private DateTime? TranslateTime(long? time)
|
||||
{
|
||||
if (time.HasValue)
|
||||
if (time.HasValue && time.Value >= 0 && time.Value <= 2650467743999999999) //maximum Windows file time 31.12.9999
|
||||
{
|
||||
return TranslateTime(time.Value);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ReadDateTimeVector(List<byte[]> dataVector, int numFiles, Action<int, DateTime?> action)
|
||||
@@ -185,9 +203,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
{
|
||||
if (boolVector[i])
|
||||
{
|
||||
action(i, ReadUInt32());
|
||||
}
|
||||
else
|
||||
{
|
||||
action(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,10 +252,14 @@ namespace SharpCompress.Common.SevenZip
|
||||
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;
|
||||
for (int j = 0; j < idSize; j++)
|
||||
{
|
||||
id |= (ulong)longID[idSize - 1 - j] << (8 * j);
|
||||
}
|
||||
coder.MethodId = new CMethodId(id);
|
||||
|
||||
if ((mainByte & 0x10) != 0)
|
||||
@@ -264,7 +290,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
|
||||
if ((mainByte & 0x80) != 0)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
numInStreams += coder.NumInStreams;
|
||||
numOutStreams += coder.NumOutStreams;
|
||||
@@ -298,9 +326,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
#endif
|
||||
|
||||
if (numInStreams < numBindPairs)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
int numPackStreams = numInStreams - numBindPairs;
|
||||
|
||||
//folder.PackStreams.Reserve(numPackStreams);
|
||||
if (numPackStreams == 1)
|
||||
{
|
||||
@@ -317,7 +348,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
|
||||
if (folder.PackStreams.Count != 1)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -417,11 +450,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
#endif
|
||||
|
||||
BlockType? type;
|
||||
for (; ; )
|
||||
for (;;)
|
||||
{
|
||||
type = ReadId();
|
||||
if (type == BlockType.End)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (type == BlockType.CRC)
|
||||
{
|
||||
packCRCs = ReadHashDigests(numPackStreams);
|
||||
@@ -434,7 +469,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
packCRCs = new List<uint?>(numPackStreams);
|
||||
for (int i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
packCRCs.Add(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -462,13 +499,14 @@ namespace SharpCompress.Common.SevenZip
|
||||
using (CStreamSwitch streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
streamSwitch.Set(this, dataVector);
|
||||
|
||||
//folders.Clear();
|
||||
//folders.Reserve(numFolders);
|
||||
folders = new List<CFolder>(numFolders);
|
||||
int index = 0;
|
||||
for (int i = 0; i < numFolders; i++)
|
||||
{
|
||||
var f = new CFolder { FirstPackStreamId = index };
|
||||
var f = new CFolder {FirstPackStreamId = index};
|
||||
folders.Add(f);
|
||||
GetNextFolderItem(f);
|
||||
index += f.PackStreams.Count;
|
||||
@@ -499,17 +537,21 @@ namespace SharpCompress.Common.SevenZip
|
||||
#endif
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
for (;;)
|
||||
{
|
||||
BlockType? type = ReadId();
|
||||
if (type == BlockType.End)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == BlockType.CRC)
|
||||
{
|
||||
List<uint?> crcs = ReadHashDigests(numFolders);
|
||||
for (int i = 0; i < numFolders; i++)
|
||||
{
|
||||
folders[i].UnpackCRC = crcs[i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -536,7 +578,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
numUnpackStreamsInFolders = null;
|
||||
|
||||
BlockType? type;
|
||||
for (; ; )
|
||||
for (;;)
|
||||
{
|
||||
type = ReadId();
|
||||
if (type == BlockType.NumUnpackStream)
|
||||
@@ -559,9 +601,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
continue;
|
||||
}
|
||||
if (type == BlockType.CRC || type == BlockType.Size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (type == BlockType.End)
|
||||
{
|
||||
break;
|
||||
}
|
||||
SkipData();
|
||||
}
|
||||
|
||||
@@ -569,7 +615,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
numUnpackStreamsInFolders = new List<int>(folders.Count);
|
||||
for (int i = 0; i < folders.Count; i++)
|
||||
{
|
||||
numUnpackStreamsInFolders.Add(1);
|
||||
}
|
||||
}
|
||||
|
||||
unpackSizes = new List<long>(folders.Count);
|
||||
@@ -579,7 +627,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
// v4.07: we check that folder is empty
|
||||
int numSubstreams = numUnpackStreamsInFolders[i];
|
||||
if (numSubstreams == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#if DEBUG
|
||||
Log.Write("#{0} StreamSizes:", i);
|
||||
#endif
|
||||
@@ -602,7 +652,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
#endif
|
||||
}
|
||||
if (type == BlockType.Size)
|
||||
{
|
||||
type = ReadId();
|
||||
}
|
||||
|
||||
int numDigests = 0;
|
||||
int numDigestsTotal = 0;
|
||||
@@ -610,13 +662,15 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
int numSubstreams = numUnpackStreamsInFolders[i];
|
||||
if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
|
||||
{
|
||||
numDigests += numSubstreams;
|
||||
}
|
||||
numDigestsTotal += numSubstreams;
|
||||
}
|
||||
|
||||
digests = null;
|
||||
|
||||
for (; ; )
|
||||
for (;;)
|
||||
{
|
||||
if (type == BlockType.CRC)
|
||||
{
|
||||
@@ -636,12 +690,16 @@ namespace SharpCompress.Common.SevenZip
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < numSubstreams; j++, digestIndex++)
|
||||
{
|
||||
digests.Add(digests2[digestIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (digestIndex != numDigests || numDigestsTotal != digests.Count)
|
||||
System.Diagnostics.Debugger.Break();
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
else if (type == BlockType.End)
|
||||
{
|
||||
@@ -649,7 +707,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
digests = new List<uint?>(numDigestsTotal);
|
||||
for (int i = 0; i < numDigestsTotal; i++)
|
||||
{
|
||||
digests.Add(null);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -693,7 +753,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
unpackSizes = null;
|
||||
digests = null;
|
||||
|
||||
for (; ; )
|
||||
for (;;)
|
||||
{
|
||||
switch (ReadId())
|
||||
{
|
||||
@@ -768,12 +828,18 @@ namespace SharpCompress.Common.SevenZip
|
||||
byte[] data = new byte[unpackSize];
|
||||
outStream.ReadExact(data, 0, data.Length);
|
||||
if (outStream.ReadByte() >= 0)
|
||||
{
|
||||
throw new InvalidOperationException("Decoded stream is longer than expected.");
|
||||
}
|
||||
dataVector.Add(data);
|
||||
|
||||
if (folder.UnpackCRCDefined)
|
||||
{
|
||||
if (CRC.Finish(CRC.Update(CRC.kInitCRC, data, 0, unpackSize)) != folder.UnpackCRC)
|
||||
{
|
||||
throw new InvalidOperationException("Decoded stream does not match expected CRC.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataVector;
|
||||
}
|
||||
@@ -842,10 +908,14 @@ namespace SharpCompress.Common.SevenZip
|
||||
db.Files.Clear();
|
||||
|
||||
if (type == BlockType.End)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != BlockType.FilesInfo)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
int numFiles = ReadNum();
|
||||
#if DEBUG
|
||||
@@ -853,18 +923,22 @@ namespace SharpCompress.Common.SevenZip
|
||||
#endif
|
||||
db.Files = new List<CFileItem>(numFiles);
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
{
|
||||
db.Files.Add(new CFileItem());
|
||||
}
|
||||
|
||||
BitVector emptyStreamVector = new BitVector(numFiles);
|
||||
BitVector emptyFileVector = null;
|
||||
BitVector antiFileVector = null;
|
||||
int numEmptyStreams = 0;
|
||||
|
||||
for (; ; )
|
||||
for (;;)
|
||||
{
|
||||
type = ReadId();
|
||||
if (type == BlockType.End)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
long size = checked((long)ReadNumber()); // TODO: throw invalid data on negative
|
||||
int oldPos = _currentReader.Offset;
|
||||
@@ -894,12 +968,34 @@ namespace SharpCompress.Common.SevenZip
|
||||
Log.Write("WinAttributes:");
|
||||
#endif
|
||||
ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr)
|
||||
{
|
||||
// Some third party implementations established an unofficial extension
|
||||
// of the 7z archive format by placing posix file attributes in the high
|
||||
// bits of the windows file attributes. This makes use of the fact that
|
||||
// the official implementation does not perform checks on this value.
|
||||
//
|
||||
// Newer versions of the official 7z GUI client will try to parse this
|
||||
// extension, thus acknowledging the unofficial use of these bits.
|
||||
//
|
||||
// For us it is safe to just discard the upper bits if they are set and
|
||||
// keep the windows attributes from the lower bits (which should be set
|
||||
// properly even if posix file attributes are present, in order to be
|
||||
// compatible with older 7z archive readers)
|
||||
//
|
||||
// Note that the 15th bit is used by some implementations to indicate
|
||||
// presence of the extension, but not all implementations do that so
|
||||
// we can't trust that bit and must ignore it.
|
||||
//
|
||||
if (attr.HasValue && (attr.Value >> 16) != 0)
|
||||
{
|
||||
db.Files[i].Attrib = attr;
|
||||
attr = attr.Value & 0x7FFFu;
|
||||
}
|
||||
|
||||
db.Files[i].Attrib = attr;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a"));
|
||||
Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a"));
|
||||
#endif
|
||||
});
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -938,7 +1034,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
#if DEBUG
|
||||
Log.Write("EmptyFile: ");
|
||||
for (int i = 0; i < numEmptyStreams; i++)
|
||||
{
|
||||
Log.Write(emptyFileVector[i] ? "x" : ".");
|
||||
}
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
@@ -947,7 +1045,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
#if DEBUG
|
||||
Log.Write("Anti: ");
|
||||
for (int i = 0; i < numEmptyStreams; i++)
|
||||
{
|
||||
Log.Write(antiFileVector[i] ? "x" : ".");
|
||||
}
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
@@ -956,12 +1056,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
Log.Write("StartPos:");
|
||||
#endif
|
||||
ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos)
|
||||
{
|
||||
db.Files[i].StartPos = startPos;
|
||||
{
|
||||
db.Files[i].StartPos = startPos;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a"));
|
||||
Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -971,12 +1071,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
Log.Write("CTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
|
||||
{
|
||||
db.Files[i].CTime = time;
|
||||
{
|
||||
db.Files[i].CTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -986,12 +1086,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
Log.Write("ATime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
|
||||
{
|
||||
db.Files[i].ATime = time;
|
||||
{
|
||||
db.Files[i].ATime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -1001,12 +1101,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
Log.Write("MTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
|
||||
{
|
||||
db.Files[i].MTime = time;
|
||||
{
|
||||
db.Files[i].MTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -1016,8 +1116,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
Log.Write("Dummy: " + size);
|
||||
#endif
|
||||
for (long j = 0; j < size; j++)
|
||||
{
|
||||
if (ReadByte() != 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SkipData(size);
|
||||
@@ -1027,7 +1131,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
// since 0.3 record sizes must be correct
|
||||
bool checkRecordsSize = (db.MajorVersion > 0 || db.MinorVersion > 2);
|
||||
if (checkRecordsSize && _currentReader.Offset - oldPos != size)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
int emptyFileIndex = 0;
|
||||
@@ -1075,11 +1181,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
// TODO: Check Signature!
|
||||
_header = new byte[0x20];
|
||||
for (int offset = 0; offset < 0x20; )
|
||||
for (int offset = 0; offset < 0x20;)
|
||||
{
|
||||
int delta = stream.Read(_header, offset, 0x20 - offset);
|
||||
if (delta == 0)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
offset += delta;
|
||||
}
|
||||
|
||||
@@ -1089,24 +1197,30 @@ namespace SharpCompress.Common.SevenZip
|
||||
public void Close()
|
||||
{
|
||||
if (_stream != null)
|
||||
{
|
||||
_stream.Dispose();
|
||||
}
|
||||
|
||||
foreach (var stream in _cachedStreams.Values)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
_cachedStreams.Clear();
|
||||
}
|
||||
|
||||
public ArchiveDatabase ReadDatabase(IPasswordProvider pass)
|
||||
{
|
||||
var db = new ArchiveDatabase();
|
||||
var db = new ArchiveDatabase(pass);
|
||||
db.Clear();
|
||||
|
||||
db.MajorVersion = _header[6];
|
||||
db.MinorVersion = _header[7];
|
||||
|
||||
if (db.MajorVersion != 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
uint crcFromArchive = DataReader.Get32(_header, 8);
|
||||
long nextHeaderOffset = (long)DataReader.Get64(_header, 0xC);
|
||||
@@ -1120,7 +1234,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
crc = CRC.Finish(crc);
|
||||
|
||||
if (crc != crcFromArchive)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
db.StartPositionAfterHeader = _streamOrigin + 0x20;
|
||||
|
||||
@@ -1131,12 +1247,15 @@ namespace SharpCompress.Common.SevenZip
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
if (nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > Int32.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (nextHeaderOffset > _streamEnding - db.StartPositionAfterHeader)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
_stream.Seek(nextHeaderOffset, SeekOrigin.Current);
|
||||
|
||||
@@ -1144,7 +1263,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
_stream.ReadExact(header, 0, header.Length);
|
||||
|
||||
if (CRC.Finish(CRC.Update(CRC.kInitCRC, header, 0, header.Length)) != nextHeaderCrc)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
using (CStreamSwitch streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
@@ -1154,9 +1275,11 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (type != BlockType.Header)
|
||||
{
|
||||
if (type != BlockType.EncodedHeader)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, pass);
|
||||
var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, db.PasswordProvider);
|
||||
|
||||
// compressed header without content is odd but ok
|
||||
if (dataVector.Count == 0)
|
||||
@@ -1166,15 +1289,19 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
|
||||
if (dataVector.Count != 1)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
streamSwitch.Set(this, dataVector[0]);
|
||||
|
||||
if (ReadId() != BlockType.Header)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
ReadHeader(db, pass);
|
||||
ReadHeader(db, db.PasswordProvider);
|
||||
}
|
||||
db.Fill();
|
||||
return db;
|
||||
@@ -1191,55 +1318,41 @@ namespace SharpCompress.Common.SevenZip
|
||||
FileIndex = fileIndex;
|
||||
FolderIndex = folderIndex;
|
||||
if (fileIndex != -1)
|
||||
{
|
||||
ExtractStatuses.Add(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FolderUnpackStream : Stream
|
||||
{
|
||||
private ArchiveDatabase _db;
|
||||
private int _startIndex;
|
||||
private List<bool> _extractStatuses;
|
||||
private readonly ArchiveDatabase _db;
|
||||
private readonly int _startIndex;
|
||||
private readonly List<bool> _extractStatuses;
|
||||
|
||||
public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List<bool> list)
|
||||
{
|
||||
this._db = db;
|
||||
this._startIndex = startIndex;
|
||||
this._extractStatuses = list;
|
||||
_db = db;
|
||||
_startIndex = startIndex;
|
||||
_extractStatuses = list;
|
||||
}
|
||||
|
||||
#region Stream
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
@@ -1278,9 +1391,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
Log.WriteLine(_db.Files[index].Name);
|
||||
#endif
|
||||
if (_db.Files[index].CrcDefined)
|
||||
{
|
||||
_stream = new CrcCheckStream(_db.Files[index].Crc.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream = new MemoryStream();
|
||||
}
|
||||
_rem = _db.Files[index].Size;
|
||||
}
|
||||
|
||||
@@ -1292,7 +1409,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
int write = count;
|
||||
if (write > _rem)
|
||||
{
|
||||
write = (int)_rem;
|
||||
}
|
||||
_stream.Write(buffer, offset, write);
|
||||
count -= write;
|
||||
_rem -= write;
|
||||
@@ -1311,7 +1430,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (_currentIndex == _extractStatuses.Count)
|
||||
{
|
||||
// we support partial extracting
|
||||
System.Diagnostics.Debugger.Break();
|
||||
Debugger.Break();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
OpenFile();
|
||||
@@ -1322,7 +1441,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
#endregion
|
||||
}
|
||||
|
||||
private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex, IPasswordProvider pw)
|
||||
private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex)
|
||||
{
|
||||
Stream s;
|
||||
if (!_cachedStreams.TryGetValue(folderIndex, out s))
|
||||
@@ -1332,44 +1451,56 @@ namespace SharpCompress.Common.SevenZip
|
||||
long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0);
|
||||
List<long> packSizes = new List<long>();
|
||||
for (int j = 0; j < folderInfo.PackStreams.Count; j++)
|
||||
{
|
||||
packSizes.Add(_db.PackSizes[packStreamIndex + j]);
|
||||
}
|
||||
|
||||
s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo,
|
||||
pw);
|
||||
_db.PasswordProvider);
|
||||
_cachedStreams.Add(folderIndex, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public Stream OpenStream(ArchiveDatabase _db, int fileIndex, IPasswordProvider pw)
|
||||
public Stream OpenStream(ArchiveDatabase _db, int fileIndex)
|
||||
{
|
||||
int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
|
||||
int numFilesInFolder = _db.NumUnpackStreamsVector[folderIndex];
|
||||
int firstFileIndex = _db.FolderStartFileIndex[folderIndex];
|
||||
if (firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
int skipCount = fileIndex - firstFileIndex;
|
||||
long skipSize = 0;
|
||||
for (int i = 0; i < skipCount; i++)
|
||||
{
|
||||
skipSize += _db.Files[firstFileIndex + i].Size;
|
||||
}
|
||||
|
||||
Stream s = GetCachedDecoderStream(_db, folderIndex, pw);
|
||||
Stream s = GetCachedDecoderStream(_db, folderIndex);
|
||||
s.Position = skipSize;
|
||||
return new ReadOnlySubStream(s, _db.Files[fileIndex].Size);
|
||||
}
|
||||
|
||||
public void Extract(ArchiveDatabase _db, int[] indices, IPasswordProvider pw)
|
||||
public void Extract(ArchiveDatabase _db, int[] indices)
|
||||
{
|
||||
int numItems;
|
||||
bool allFilesMode = (indices == null);
|
||||
if (allFilesMode)
|
||||
{
|
||||
numItems = _db.Files.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
numItems = indices.Length;
|
||||
}
|
||||
|
||||
if (numItems == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<CExtractFolderInfo> extractFolderInfoVector = new List<CExtractFolderInfo>();
|
||||
for (int i = 0; i < numItems; i++)
|
||||
@@ -1384,27 +1515,37 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
|
||||
if (extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last().FolderIndex)
|
||||
{
|
||||
extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex));
|
||||
}
|
||||
|
||||
CExtractFolderInfo efi = extractFolderInfoVector.Last();
|
||||
|
||||
int startIndex = _db.FolderStartFileIndex[folderIndex];
|
||||
for (int index = efi.ExtractStatuses.Count; index <= fileIndex - startIndex; index++)
|
||||
{
|
||||
efi.ExtractStatuses.Add(index == fileIndex - startIndex);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CExtractFolderInfo efi in extractFolderInfoVector)
|
||||
{
|
||||
int startIndex;
|
||||
if (efi.FileIndex != -1)
|
||||
{
|
||||
startIndex = efi.FileIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex = _db.FolderStartFileIndex[efi.FolderIndex];
|
||||
}
|
||||
|
||||
var outStream = new FolderUnpackStream(_db, 0, startIndex, efi.ExtractStatuses);
|
||||
|
||||
if (efi.FileIndex != -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int folderIndex = efi.FolderIndex;
|
||||
CFolder folderInfo = _db.Folders[folderIndex];
|
||||
@@ -1414,18 +1555,22 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
List<long> packSizes = new List<long>();
|
||||
for (int j = 0; j < folderInfo.PackStreams.Count; j++)
|
||||
{
|
||||
packSizes.Add(_db.PackSizes[packStreamIndex + j]);
|
||||
}
|
||||
|
||||
// TODO: If the decoding fails the last file may be extracted incompletely. Delete it?
|
||||
|
||||
Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(),
|
||||
folderInfo, pw);
|
||||
folderInfo, _db.PasswordProvider);
|
||||
byte[] buffer = new byte[4 << 10];
|
||||
for (; ; )
|
||||
for (;;)
|
||||
{
|
||||
int processed = s.Read(buffer, 0, buffer.Length);
|
||||
if (processed == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
outStream.Write(buffer, 0, processed);
|
||||
}
|
||||
}
|
||||
@@ -1443,4 +1588,4 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,19 +12,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
public bool HasStream { get; internal set; }
|
||||
public bool IsDir { get; internal set; }
|
||||
|
||||
public bool CrcDefined
|
||||
{
|
||||
get { return Crc != null; }
|
||||
}
|
||||
public bool CrcDefined => Crc != null;
|
||||
|
||||
public bool AttribDefined
|
||||
{
|
||||
get { return Attrib != null; }
|
||||
}
|
||||
public bool AttribDefined => Attrib != null;
|
||||
|
||||
public void SetAttrib(uint attrib)
|
||||
{
|
||||
this.Attrib = attrib;
|
||||
Attrib = attrib;
|
||||
}
|
||||
|
||||
public DateTime? CTime { get; internal set; }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SharpCompress.Compressor.LZMA;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
@@ -13,19 +13,22 @@ namespace SharpCompress.Common.SevenZip
|
||||
internal List<long> UnpackSizes = new List<long>();
|
||||
internal uint? UnpackCRC;
|
||||
|
||||
internal bool UnpackCRCDefined
|
||||
{
|
||||
get { return UnpackCRC != null; }
|
||||
}
|
||||
internal bool UnpackCRCDefined => UnpackCRC != null;
|
||||
|
||||
public long GetUnpackSize()
|
||||
{
|
||||
if (UnpackSizes.Count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = UnpackSizes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (FindBindPairForOutStream(i) < 0)
|
||||
{
|
||||
return UnpackSizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
@@ -34,7 +37,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < Coders.Count; i++)
|
||||
{
|
||||
count += Coders[i].NumOutStreams;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -42,8 +47,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
public int FindBindPairForInStream(int inStreamIndex)
|
||||
{
|
||||
for (int i = 0; i < BindPairs.Count; i++)
|
||||
{
|
||||
if (BindPairs[i].InIndex == inStreamIndex)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -51,8 +60,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
public int FindBindPairForOutStream(int outStreamIndex)
|
||||
{
|
||||
for (int i = 0; i < BindPairs.Count; i++)
|
||||
{
|
||||
if (BindPairs[i].OutIndex == outStreamIndex)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -60,8 +73,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
public int FindPackStreamArrayIndex(int inStreamIndex)
|
||||
{
|
||||
for (int i = 0; i < PackStreams.Count; i++)
|
||||
{
|
||||
if (PackStreams[i] == inStreamIndex)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -69,8 +86,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
public bool IsEncrypted()
|
||||
{
|
||||
for (int i = Coders.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (Coders[i].MethodId == CMethodId.kAES)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -82,25 +103,39 @@ namespace SharpCompress.Common.SevenZip
|
||||
const int kNumBindsMax = 32;
|
||||
|
||||
if (Coders.Count > kNumCodersMax || BindPairs.Count > kNumBindsMax)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
var v = new BitVector(BindPairs.Count + PackStreams.Count);
|
||||
|
||||
for (int i = 0; i < BindPairs.Count; i++)
|
||||
{
|
||||
if (v.GetAndSet(BindPairs[i].InIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < PackStreams.Count; i++)
|
||||
{
|
||||
if (v.GetAndSet(PackStreams[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var v = new BitVector(UnpackSizes.Count);
|
||||
for (int i = 0; i < BindPairs.Count; i++)
|
||||
{
|
||||
if (v.GetAndSet(BindPairs[i].OutIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint[] mask = new uint[kMaskSize];
|
||||
@@ -112,9 +147,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
CCoderInfo coder = Coders[i];
|
||||
for (int j = 0; j < coder.NumInStreams; j++)
|
||||
{
|
||||
inStreamToCoder.Add(i);
|
||||
}
|
||||
for (int j = 0; j < coder.NumOutStreams; j++)
|
||||
{
|
||||
outStreamToCoder.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < BindPairs.Count; i++)
|
||||
@@ -125,13 +164,23 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaskSize; i++)
|
||||
{
|
||||
for (int j = 0; j < kMaskSize; j++)
|
||||
{
|
||||
if (((1u << j) & mask[i]) != 0)
|
||||
{
|
||||
mask[i] |= mask[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaskSize; i++)
|
||||
{
|
||||
if (((1u << i) & mask[i]) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
public CMethodId(ulong id)
|
||||
{
|
||||
this.Id = id;
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is CMethodId && (CMethodId) obj == this;
|
||||
return obj is CMethodId && (CMethodId)obj == this;
|
||||
}
|
||||
|
||||
public bool Equals(CMethodId other)
|
||||
@@ -48,7 +48,9 @@
|
||||
{
|
||||
int bytes = 0;
|
||||
for (ulong value = Id; value != 0; value >>= 8)
|
||||
{
|
||||
bytes++;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Compressor.LZMA;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
@@ -47,7 +46,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
int dataIndex = archive.ReadNum();
|
||||
if (dataIndex < 0 || dataIndex >= dataVector.Count)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteLine("[switch to stream {0}]", dataIndex);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SharpCompress.Compressor.LZMA;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
@@ -11,31 +11,30 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
public static uint Get32(byte[] buffer, int offset)
|
||||
{
|
||||
return (uint) buffer[offset]
|
||||
+ ((uint) buffer[offset + 1] << 8)
|
||||
+ ((uint) buffer[offset + 2] << 16)
|
||||
+ ((uint) buffer[offset + 3] << 24);
|
||||
return buffer[offset]
|
||||
+ ((uint)buffer[offset + 1] << 8)
|
||||
+ ((uint)buffer[offset + 2] << 16)
|
||||
+ ((uint)buffer[offset + 3] << 24);
|
||||
}
|
||||
|
||||
public static ulong Get64(byte[] buffer, int offset)
|
||||
{
|
||||
return (ulong) buffer[offset]
|
||||
+ ((ulong) buffer[offset + 1] << 8)
|
||||
+ ((ulong) buffer[offset + 2] << 16)
|
||||
+ ((ulong) buffer[offset + 3] << 24)
|
||||
+ ((ulong) buffer[offset + 4] << 32)
|
||||
+ ((ulong) buffer[offset + 5] << 40)
|
||||
+ ((ulong) buffer[offset + 6] << 48)
|
||||
+ ((ulong) buffer[offset + 7] << 56);
|
||||
return buffer[offset]
|
||||
+ ((ulong)buffer[offset + 1] << 8)
|
||||
+ ((ulong)buffer[offset + 2] << 16)
|
||||
+ ((ulong)buffer[offset + 3] << 24)
|
||||
+ ((ulong)buffer[offset + 4] << 32)
|
||||
+ ((ulong)buffer[offset + 5] << 40)
|
||||
+ ((ulong)buffer[offset + 6] << 48)
|
||||
+ ((ulong)buffer[offset + 7] << 56);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Variables
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _offset;
|
||||
private int _ending;
|
||||
private readonly byte[] _buffer;
|
||||
private readonly int _ending;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -44,38 +43,43 @@ namespace SharpCompress.Common.SevenZip
|
||||
public DataReader(byte[] buffer, int offset, int length)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_offset = offset;
|
||||
Offset = offset;
|
||||
_ending = offset + length;
|
||||
}
|
||||
|
||||
public int Offset
|
||||
{
|
||||
get { return _offset; }
|
||||
}
|
||||
public int Offset { get; private set; }
|
||||
|
||||
public Byte ReadByte()
|
||||
{
|
||||
if (_offset >= _ending)
|
||||
if (Offset >= _ending)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
return _buffer[_offset++];
|
||||
return _buffer[Offset++];
|
||||
}
|
||||
|
||||
public void ReadBytes(byte[] buffer, int offset, int length)
|
||||
{
|
||||
if (length > _ending - _offset)
|
||||
if (length > _ending - Offset)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
while (length-- > 0)
|
||||
buffer[offset++] = _buffer[_offset++];
|
||||
{
|
||||
buffer[offset++] = _buffer[Offset++];
|
||||
}
|
||||
}
|
||||
|
||||
public void SkipData(long size)
|
||||
{
|
||||
if (size > _ending - _offset)
|
||||
if (size > _ending - Offset)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
_offset += (int) size;
|
||||
Offset += (int)size;
|
||||
#if DEBUG
|
||||
Log.WriteLine("SkipData {0}", size);
|
||||
#endif
|
||||
@@ -83,15 +87,17 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
public void SkipData()
|
||||
{
|
||||
SkipData(checked((long) ReadNumber()));
|
||||
SkipData(checked((long)ReadNumber()));
|
||||
}
|
||||
|
||||
public ulong ReadNumber()
|
||||
{
|
||||
if (_offset >= _ending)
|
||||
if (Offset >= _ending)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
byte firstByte = _buffer[_offset++];
|
||||
byte firstByte = _buffer[Offset++];
|
||||
byte mask = 0x80;
|
||||
ulong value = 0;
|
||||
|
||||
@@ -100,14 +106,16 @@ namespace SharpCompress.Common.SevenZip
|
||||
if ((firstByte & mask) == 0)
|
||||
{
|
||||
ulong highPart = firstByte & (mask - 1u);
|
||||
value += highPart << (i*8);
|
||||
value += highPart << (i * 8);
|
||||
return value;
|
||||
}
|
||||
|
||||
if (_offset >= _ending)
|
||||
if (Offset >= _ending)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
value |= (ulong) _buffer[_offset++] << (8*i);
|
||||
value |= (ulong)_buffer[Offset++] << (8 * i);
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
@@ -118,48 +126,58 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
ulong value = ReadNumber();
|
||||
if (value > Int32.MaxValue)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
return (int) value;
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
public uint ReadUInt32()
|
||||
{
|
||||
if (_offset + 4 > _ending)
|
||||
if (Offset + 4 > _ending)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
uint res = Get32(_buffer, _offset);
|
||||
_offset += 4;
|
||||
uint res = Get32(_buffer, Offset);
|
||||
Offset += 4;
|
||||
return res;
|
||||
}
|
||||
|
||||
public ulong ReadUInt64()
|
||||
{
|
||||
if (_offset + 8 > _ending)
|
||||
if (Offset + 8 > _ending)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
ulong res = Get64(_buffer, _offset);
|
||||
_offset += 8;
|
||||
ulong res = Get64(_buffer, Offset);
|
||||
Offset += 8;
|
||||
return res;
|
||||
}
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
int ending = _offset;
|
||||
int ending = Offset;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (ending + 2 > _ending)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
if (_buffer[ending] == 0 && _buffer[ending + 1] == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ending += 2;
|
||||
}
|
||||
|
||||
string str = Encoding.Unicode.GetString(_buffer, _offset, ending - _offset);
|
||||
_offset = ending + 2;
|
||||
string str = Encoding.Unicode.GetString(_buffer, Offset, ending - Offset);
|
||||
Offset = ending + 2;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,79 +7,37 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
internal SevenZipEntry(SevenZipFilePart filePart)
|
||||
{
|
||||
this.FilePart = filePart;
|
||||
FilePart = filePart;
|
||||
}
|
||||
|
||||
internal SevenZipFilePart FilePart { get; private set; }
|
||||
internal SevenZipFilePart FilePart { get; }
|
||||
|
||||
public override CompressionType CompressionType
|
||||
{
|
||||
get { return FilePart.CompressionType; }
|
||||
}
|
||||
public override CompressionType CompressionType => FilePart.CompressionType;
|
||||
|
||||
public override long Crc
|
||||
{
|
||||
get { return FilePart.Header.Crc ?? 0; }
|
||||
}
|
||||
public override long Crc => FilePart.Header.Crc ?? 0;
|
||||
|
||||
public override string Key
|
||||
{
|
||||
get { return FilePart.Header.Name; }
|
||||
}
|
||||
public override string Key => FilePart.Header.Name;
|
||||
|
||||
public override long CompressedSize
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
public override long CompressedSize => 0;
|
||||
|
||||
public override long Size
|
||||
{
|
||||
get { return (long) FilePart.Header.Size; }
|
||||
}
|
||||
public override long Size => FilePart.Header.Size;
|
||||
|
||||
public override DateTime? LastModifiedTime
|
||||
{
|
||||
get { return FilePart.Header.MTime; }
|
||||
}
|
||||
public override DateTime? LastModifiedTime => FilePart.Header.MTime;
|
||||
|
||||
public override DateTime? CreatedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
public override DateTime? CreatedTime => null;
|
||||
|
||||
public override DateTime? LastAccessedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
public override DateTime? LastAccessedTime => null;
|
||||
|
||||
public override DateTime? ArchivedTime
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
public override DateTime? ArchivedTime => null;
|
||||
|
||||
public override bool IsEncrypted
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool IsEncrypted => false;
|
||||
|
||||
public override bool IsDirectory
|
||||
{
|
||||
get { return FilePart.Header.IsDir; }
|
||||
}
|
||||
public override bool IsDirectory => FilePart.Header.IsDir;
|
||||
|
||||
public override bool IsSplit
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override bool IsSplit => false;
|
||||
|
||||
public override int? Attrib
|
||||
{
|
||||
get { return (int) FilePart.Header.Attrib; }
|
||||
}
|
||||
public override int? Attrib => (int)FilePart.Header.Attrib;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts
|
||||
{
|
||||
get { return FilePart.AsEnumerable<FilePart>(); }
|
||||
}
|
||||
internal override IEnumerable<FilePart> Parts => FilePart.AsEnumerable<FilePart>();
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,15 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
internal class SevenZipFilePart : FilePart
|
||||
{
|
||||
private CompressionType? type;
|
||||
private Stream stream;
|
||||
private ArchiveDatabase database;
|
||||
private CompressionType? _type;
|
||||
private readonly Stream _stream;
|
||||
private readonly ArchiveDatabase _database;
|
||||
|
||||
internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry)
|
||||
internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry, ArchiveEncoding archiveEncoding)
|
||||
: base(archiveEncoding)
|
||||
{
|
||||
this.stream = stream;
|
||||
this.database = database;
|
||||
this._stream = stream;
|
||||
this._database = database;
|
||||
Index = index;
|
||||
Header = fileEntry;
|
||||
if (Header.HasStream)
|
||||
@@ -24,14 +25,11 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
|
||||
internal Stream BaseStream { get; private set; }
|
||||
internal CFileItem Header { get; private set; }
|
||||
internal CFolder Folder { get; private set; }
|
||||
internal int Index { get; private set; }
|
||||
internal CFileItem Header { get; }
|
||||
internal CFolder Folder { get; }
|
||||
internal int Index { get; }
|
||||
|
||||
internal override string FilePartName
|
||||
{
|
||||
get { return Header.Name; }
|
||||
}
|
||||
internal override string FilePartName => Header.Name;
|
||||
|
||||
internal override Stream GetRawStream()
|
||||
{
|
||||
@@ -44,14 +42,14 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var folderStream = database.GetFolderStream(stream, Folder, null);
|
||||
var folderStream = _database.GetFolderStream(_stream, Folder, _database.PasswordProvider);
|
||||
|
||||
int firstFileIndex = database.FolderStartFileIndex[database.Folders.IndexOf(Folder)];
|
||||
int firstFileIndex = _database.FolderStartFileIndex[_database.Folders.IndexOf(Folder)];
|
||||
int skipCount = Index - firstFileIndex;
|
||||
long skipSize = 0;
|
||||
for (int i = 0; i < skipCount; i++)
|
||||
{
|
||||
skipSize += database.Files[firstFileIndex + i].Size;
|
||||
skipSize += _database.Files[firstFileIndex + i].Size;
|
||||
}
|
||||
if (skipSize > 0)
|
||||
{
|
||||
@@ -64,11 +62,11 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
get
|
||||
{
|
||||
if (type == null)
|
||||
if (_type == null)
|
||||
{
|
||||
type = GetCompression();
|
||||
_type = GetCompression();
|
||||
}
|
||||
return type.Value;
|
||||
return _type.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,20 +85,20 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
var coder = Folder.Coders.First();
|
||||
switch (coder.MethodId.Id)
|
||||
{
|
||||
{
|
||||
case k_LZMA:
|
||||
case k_LZMA2:
|
||||
{
|
||||
return CompressionType.LZMA;
|
||||
}
|
||||
{
|
||||
return CompressionType.LZMA;
|
||||
}
|
||||
case k_PPMD:
|
||||
{
|
||||
return CompressionType.PPMd;
|
||||
}
|
||||
{
|
||||
return CompressionType.PPMd;
|
||||
}
|
||||
case k_BZip2:
|
||||
{
|
||||
return CompressionType.BZip2;
|
||||
}
|
||||
{
|
||||
return CompressionType.BZip2;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
public class SevenZipVolume : Volume
|
||||
{
|
||||
public SevenZipVolume(Stream stream, Options options)
|
||||
: base(stream, options)
|
||||
public SevenZipVolume(Stream stream, ReaderOptions readerFactoryOptions)
|
||||
: base(stream, readerFactoryOptions)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
internal enum EntryType : byte
|
||||
{
|
||||
File = 0,
|
||||
OldFile = (byte) '0',
|
||||
HardLink = (byte) '1',
|
||||
SymLink = (byte) '2',
|
||||
CharDevice = (byte) '3',
|
||||
BlockDevice = (byte) '4',
|
||||
Directory = (byte) '5',
|
||||
Fifo = (byte) '6',
|
||||
LongLink = (byte) 'K',
|
||||
LongName = (byte) 'L',
|
||||
SparseFile = (byte) 'S',
|
||||
VolumeHeader = (byte) 'V',
|
||||
GlobalExtendedHeader = (byte) 'g',
|
||||
OldFile = (byte)'0',
|
||||
HardLink = (byte)'1',
|
||||
SymLink = (byte)'2',
|
||||
CharDevice = (byte)'3',
|
||||
BlockDevice = (byte)'4',
|
||||
Directory = (byte)'5',
|
||||
Fifo = (byte)'6',
|
||||
LongLink = (byte)'K',
|
||||
LongName = (byte)'L',
|
||||
SparseFile = (byte)'S',
|
||||
VolumeHeader = (byte)'V',
|
||||
GlobalExtendedHeader = (byte)'g'
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SharpCompress.Converter;
|
||||
using SharpCompress.Converters;
|
||||
|
||||
namespace SharpCompress.Common.Tar.Headers
|
||||
{
|
||||
@@ -9,7 +9,13 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
{
|
||||
internal static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
public TarHeader(ArchiveEncoding archiveEncoding)
|
||||
{
|
||||
ArchiveEncoding = archiveEncoding;
|
||||
}
|
||||
|
||||
internal string Name { get; set; }
|
||||
|
||||
//internal int Mode { get; set; }
|
||||
//internal int UserId { get; set; }
|
||||
//internal string UserName { get; set; }
|
||||
@@ -19,6 +25,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
internal DateTime LastModifiedTime { get; set; }
|
||||
internal EntryType EntryType { get; set; }
|
||||
internal Stream PackedStream { get; set; }
|
||||
internal ArchiveEncoding ArchiveEncoding { get; }
|
||||
|
||||
internal const int BlockSize = 512;
|
||||
|
||||
@@ -30,7 +37,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
WriteOctalBytes(0, buffer, 108, 8); // owner ID
|
||||
WriteOctalBytes(0, buffer, 116, 8); // group ID
|
||||
|
||||
//Encoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
|
||||
//ArchiveEncoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
|
||||
if (Name.Length > 100)
|
||||
{
|
||||
// Set mock filename and filetype to indicate the next block is the actual name of the file
|
||||
@@ -71,13 +78,15 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
|
||||
private void WriteLongFilenameHeader(Stream output)
|
||||
{
|
||||
byte[] nameBytes = ArchiveEncoding.Default.GetBytes(Name);
|
||||
byte[] nameBytes = ArchiveEncoding.Encode(Name);
|
||||
output.Write(nameBytes, 0, nameBytes.Length);
|
||||
|
||||
// pad to multiple of BlockSize bytes, and make sure a terminating null is added
|
||||
int numPaddingBytes = BlockSize - (nameBytes.Length % BlockSize);
|
||||
if (numPaddingBytes == 0)
|
||||
{
|
||||
numPaddingBytes = BlockSize;
|
||||
}
|
||||
output.Write(new byte[numPaddingBytes], 0, numPaddingBytes);
|
||||
}
|
||||
|
||||
@@ -96,7 +105,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
}
|
||||
else
|
||||
{
|
||||
Name = ArchiveEncoding.Default.GetString(buffer, 0, 100).TrimNulls();
|
||||
Name = ArchiveEncoding.Decode(buffer, 0, 100).TrimNulls();
|
||||
}
|
||||
|
||||
EntryType = ReadEntryType(buffer);
|
||||
@@ -108,12 +117,12 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
long unixTimeStamp = ReadASCIIInt64Base8(buffer, 136, 11);
|
||||
LastModifiedTime = Epoch.AddSeconds(unixTimeStamp).ToLocalTime();
|
||||
|
||||
Magic = ArchiveEncoding.Default.GetString(buffer, 257, 6).TrimNulls();
|
||||
Magic = ArchiveEncoding.Decode(buffer, 257, 6).TrimNulls();
|
||||
|
||||
if (!string.IsNullOrEmpty(Magic)
|
||||
&& "ustar".Equals(Magic))
|
||||
{
|
||||
string namePrefix = ArchiveEncoding.Default.GetString(buffer, 345, 157);
|
||||
string namePrefix = ArchiveEncoding.Decode(buffer, 345, 157);
|
||||
namePrefix = namePrefix.TrimNulls();
|
||||
if (!string.IsNullOrEmpty(namePrefix))
|
||||
{
|
||||
@@ -131,12 +140,16 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
private string ReadLongName(BinaryReader reader, byte[] buffer)
|
||||
{
|
||||
var size = ReadSize(buffer);
|
||||
var nameLength = (int) size;
|
||||
var nameLength = (int)size;
|
||||
var nameBytes = reader.ReadBytes(nameLength);
|
||||
var remainingBytesToRead = BlockSize - (nameLength%BlockSize);
|
||||
var remainingBytesToRead = BlockSize - (nameLength % BlockSize);
|
||||
|
||||
// Read the rest of the block and discard the data
|
||||
if (remainingBytesToRead < BlockSize) reader.ReadBytes(remainingBytesToRead);
|
||||
return ArchiveEncoding.Default.GetString(nameBytes, 0, nameBytes.Length).TrimNulls();
|
||||
if (remainingBytesToRead < BlockSize)
|
||||
{
|
||||
reader.ReadBytes(remainingBytesToRead);
|
||||
}
|
||||
return ArchiveEncoding.Decode(nameBytes, 0, nameBytes.Length).TrimNulls();
|
||||
}
|
||||
|
||||
private static EntryType ReadEntryType(byte[] buffer)
|
||||
@@ -157,9 +170,9 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(BlockSize);
|
||||
|
||||
if (buffer.Length < BlockSize)
|
||||
if (buffer.Length != 0 && buffer.Length < BlockSize)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
throw new InvalidOperationException("Buffer is invalid size");
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user