Compare commits

..

1 Commits

322 changed files with 2139 additions and 7676 deletions

View File

@@ -1,15 +0,0 @@
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
View File

@@ -2,4 +2,4 @@
* text=auto
# need original files to be windows
*.txt text eol=crlf
test/TestArchives/Original/*.txt eol=crlf

3
.gitignore vendored
View File

@@ -10,8 +10,7 @@ TestResults/
*.nupkg
packages/*/
project.lock.json
tests/TestArchives/Scratch
test/TestArchives/Scratch
.vs
tools
.vscode
.idea/

View File

@@ -1,61 +1,33 @@
# Formats
# Archive 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.
Archive classes allow random access to a seekable stream.
Reader classes allow forward-only reading
Writer classes allow forward-only Writing
## Supported Format Table
| Archive Format | Compression Format(s) | Compress/Decompress | Archive API | Reader API | Writer API |
| --- | --- | --- | --- | --- | --- |
| Rar | Rar | Decompress (1) | RarArchive | RarReader | N/A |
| Zip (2) | None, DEFLATE, 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 |
| Zip (2) | None, DEFLATE, BZip2, LZMA/LZMA2, PPMd | Both | ZipArchive | ZipReader | ZipWriter |
| Tar | None, BZip2, GZip, LZip | Both | TarArchive | TarReader | TarWriter (3) |
| GZip (single file) | GZip | Both | GZipArchive | GZipReader | GZipWriter |
| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | N/A | N/A |
| 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.
2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported.
3. The Tar format requires a file size in the header. If no size is specified to the TarWriter and the stream is not seekable, then an exception will be thrown.
4. The 7Zip format doesn't allow for reading as a forward-only stream so 7Zip is only supported through the Archive API
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.
## Compressors
For those who want to directly compress/decompress bits
| 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.
| LZipStream | Decompress |

View File

@@ -1,247 +0,0 @@
#### 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

View File

@@ -1,30 +1,16 @@
# SharpCompress
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.
SharpCompress is a compression library for .NET/Mono/Silverlight/WP7 that can unrar, un7zip, unzip, untar unbzip2 and ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip are implemented.
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
AppVeyor Build -
[![Build status](https://ci.appveyor.com/api/projects/status/voxg971oemmvxh1e/branch/master?svg=true)](https://ci.appveyor.com/project/adamhathcock/sharpcompress/branch/master)
Circle CI Build -
[![CircleCI](https://circleci.com/gh/adamhathcock/sharpcompress.svg?style=svg)](https://circleci.com/gh/adamhathcock/sharpcompress)
## Need Help?
Post Issues on Github!
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
Hi everyone. I hope you're using SharpCompress and finding it useful. Please give me feedback on what you'd like to see changed especially as far as usability goes. New feature suggestions are always welcome as well. I would also like to know what projects SharpCompress is being used in. I like seeing how it is used to give me ideas for future versions. Thanks!
@@ -39,63 +25,12 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
* RAR 5 support
* 7Zip writing
* Zip64 (Need writing and extend Reading)
* Zip64
* Multi-volume Zip support.
* RAR5 support
## 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)
@@ -182,7 +117,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)
XZ implementation based on: https://github.com/sambott/XZ.NET by @sambott
Some Help/Discussion: https://sharpcompress.codeplex.com/discussions
7Zip implementation based on: https://code.google.com/p/managed-lzma/

View File

@@ -1,38 +1,44 @@
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
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

View File

@@ -45,14 +45,10 @@
<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>
@@ -118,11 +114,6 @@
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=NAMESPACE_005FALIAS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FRESOURCE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</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>

Binary file not shown.

View File

@@ -1,20 +1,17 @@
version: '{build}'
image: Visual Studio 2017
version: '0.13.{build}'
pull_requests:
do_not_increment_build_number: true
branches:
only:
- master
nuget:
disable_publish_on_pr: true
init:
- git config --global core.autocrlf true
build_script:
- ps: .\build.ps1
test: off
cache:
- tools -> build.cake
- tools -> build.ps1
artifacts:
- path: src\SharpCompress\bin\Release\*.nupkg
- path: nupkgs\*.nupkg
name: NuPkgs

View File

@@ -1,89 +1,229 @@
#addin "Cake.Json"
#addin "nuget:?package=NuGet.Core"
using NuGet;
//////////////////////////////////////////////////////////////////////
// ARGUMENTS
//////////////////////////////////////////////////////////////////////
var target = Argument("target", "Default");
var tag = Argument("tag", "cake");
var apiKey = Argument("apiKey", "");
var repo = Argument("repo", "");
//////////////////////////////////////////////////////////////////////
// PREPARATION
//////////////////////////////////////////////////////////////////////
var sources = new [] { "https://api.nuget.org/v3/index.json" };
var publishTarget = "";
Warning("=============");
var globalPath = MakeFullPath("global.json");
var nupkgs = MakeFullPath("nupkgs");
Warning("Operating on global.json: " + globalPath);
Warning("=============");
//////////////////////////////////////////////////////////////////////
// FUNCTIONS
//////////////////////////////////////////////////////////////////////
string MakeFullPath(string relativePath)
{
if (string.IsNullOrEmpty(repo))
{
return MakeAbsolute(new DirectoryPath(relativePath)).ToString();
}
if (!System.IO.Path.IsPathRooted(repo))
{
return MakeAbsolute(new DirectoryPath(System.IO.Path.Combine(repo,relativePath))).ToString();
}
return System.IO.Path.Combine(repo, relativePath);
}
IEnumerable<string> GetAllProjects()
{
var global = DeserializeJsonFromFile<JObject>(globalPath);
var projs = global["projects"].Select(x => x.ToString());
foreach(var y in projs)
{
yield return MakeFullPath(y);
}
}
IEnumerable<string> GetSourceProjects()
{
return GetAllProjects().Where(x => x.EndsWith("src"));
}
IEnumerable<string> GetTestProjects()
{
return GetAllProjects().Where(x => x.EndsWith("test"));
}
IEnumerable<string> GetFrameworks(string path)
{
var projectJObject = DeserializeJsonFromFile<JObject>(path);
foreach(var prop in ((JObject)projectJObject["frameworks"]).Properties())
{
yield return prop.Name;
}
}
string GetVersion(string path)
{
var projectJObject = DeserializeJsonFromFile<JObject>(path);
return ((JToken)projectJObject["version"]).ToString();
}
IEnumerable<string> GetProjectJsons(IEnumerable<string> projects)
{
foreach(var proj in projects)
{
foreach(var projectJson in GetFiles(proj + "/**/project.json"))
{
yield return MakeFullPath(projectJson.ToString());
}
}
}
bool IsNuGetPublished (FilePath file, string nugetSource)
{
var pkg = new ZipPackage(file.ToString());
var repo = PackageRepositoryFactory.Default.CreateRepository(nugetSource);
var packages = repo.FindPackagesById(pkg.Id);
var version = SemanticVersion.Parse(pkg.Version.ToString());
//Filter the list of packages that are not Release (Stable) versions
var exists = packages.Any (p => p.Version == version);
return exists;
}
//////////////////////////////////////////////////////////////////////
// TASKS
//////////////////////////////////////////////////////////////////////
Task("Restore")
.Does(() =>
.Does(() =>
{
DotNetCoreRestore(".");
var settings = new DotNetCoreRestoreSettings
{
Sources = sources,
NoCache = true
};
foreach(var project in GetProjectJsons(GetSourceProjects().Concat(GetTestProjects())))
{
DotNetCoreRestore(project, settings);
}
});
Task("Build")
.IsDependentOn("Restore")
.Does(() =>
.Does(() =>
{
if (IsRunningOnWindows())
var settings = new DotNetCoreBuildSettings
{
MSBuild("./sharpcompress.sln", c =>
{
c.SetConfiguration("Release")
.SetVerbosity(Verbosity.Minimal)
.UseToolVersion(MSBuildToolVersion.VS2017);
});
}
else
Configuration = "Release"
};
foreach(var project in GetProjectJsons(GetSourceProjects().Concat(GetTestProjects())))
{
var settings = new DotNetCoreBuildSettings
foreach(var framework in GetFrameworks(project))
{
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);
}
Information("Building: {0} on Framework: {1}", project, framework);
Information("========");
settings.Framework = framework;
DotNetCoreBuild(project, settings);
}
}
});
Task("Test")
.IsDependentOn("Build")
.Does(() =>
{
var files = GetFiles("tests/**/*.csproj");
foreach(var file in files)
.Does(() =>
{
var settings = new DotNetCoreTestSettings
{
var settings = new DotNetCoreTestSettings
{
Configuration = "Release",
Framework = "netcoreapp2.0"
};
DotNetCoreTest(file.ToString(), settings);
Configuration = "Release",
Verbose = true
};
foreach(var project in GetProjectJsons(GetTestProjects()))
{
settings.Framework = GetFrameworks(project).First();
DotNetCoreTest(project.ToString(), settings);
}
}).ReportError(exception =>
{
Error(exception.ToString());
});
Task("Pack")
.IsDependentOn("Build")
.Does(() =>
{
if (IsRunningOnWindows())
.Does(() =>
{
if (DirectoryExists(nupkgs))
{
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");
DeleteDirectory(nupkgs, true);
}
CreateDirectory(nupkgs);
var settings = new DotNetCorePackSettings
{
Configuration = "Release",
OutputDirectory = nupkgs
};
foreach(var project in GetProjectJsons(GetSourceProjects()))
{
DotNetCorePack(project, settings);
}
});
Task("Publish")
.IsDependentOn("Restore")
.IsDependentOn("Build")
.IsDependentOn("Test")
.IsDependentOn("Pack")
.Does(() =>
{
var packages = GetFiles(nupkgs + "/*.nupkg");
foreach(var package in packages)
{
if (package.ToString().Contains("symbols"))
{
Warning("Skipping Symbols package " + package);
continue;
}
if (IsNuGetPublished(package, sources[1]))
{
throw new InvalidOperationException(package + " is already published.");
}
NuGetPush(package, new NuGetPushSettings{
ApiKey = apiKey,
Verbosity = NuGetVerbosity.Detailed,
Source = publishTarget
});
}
});
//////////////////////////////////////////////////////////////////////
// TASK TARGETS
//////////////////////////////////////////////////////////////////////
Task("Default")
.IsDependentOn("Restore")
.IsDependentOn("Build")
.IsDependentOn("Test")
.IsDependentOn("Pack");
Task("RunTests")
.IsDependentOn("Restore")
.IsDependentOn("Build")
.IsDependentOn("Test");
//////////////////////////////////////////////////////////////////////
// EXECUTION
//////////////////////////////////////////////////////////////////////
RunTarget(target);

250
build.ps1
View File

@@ -1,41 +1,22 @@
##########################################################################
# 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()]
@@ -46,183 +27,104 @@ Param(
[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"
}
$CakeVersion = "0.16.1"
$DotNetChannel = "preview";
$DotNetVersion = "1.0.0-preview2-003131";
$DotNetInstallerUri = "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-preview2/scripts/obtain/dotnet-install.ps1";
$NugetUrl = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
# 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
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
$ToolPath = Join-Path $PSScriptRoot "tools"
if (!(Test-Path $ToolPath)) {
Write-Verbose "Creating tools directory..."
New-Item -Path $ToolPath -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."
}
}
###########################################################################
# INSTALL .NET CORE CLI
###########################################################################
# 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
Function Remove-PathVariable([string]$VariableToRemove)
{
$path = [Environment]::GetEnvironmentVariable("PATH", "User")
if ($path -ne $null)
{
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
$newItems = $path.Split(';', [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove }
[Environment]::SetEnvironmentVariable("PATH", [System.String]::Join(';', $newItems), "User")
}
$path = [Environment]::GetEnvironmentVariable("PATH", "Process")
if ($path -ne $null)
{
$newItems = $path.Split(';', [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove }
[Environment]::SetEnvironmentVariable("PATH", [System.String]::Join(';', $newItems), "Process")
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore addins from NuGet
if (Test-Path $ADDINS_PACKAGES_CONFIG) {
Push-Location
Set-Location $ADDINS_DIR
# Get .NET Core CLI path if installed.
$FoundDotNetCliVersion = $null;
if (Get-Command dotnet -ErrorAction SilentlyContinue) {
$FoundDotNetCliVersion = dotnet --version;
}
Write-Verbose -Message "Restoring addins from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
if($FoundDotNetCliVersion -ne $DotNetVersion) {
$InstallPath = Join-Path $PSScriptRoot ".dotnet"
if (!(Test-Path $InstallPath)) {
mkdir -Force $InstallPath | Out-Null;
}
(New-Object System.Net.WebClient).DownloadFile($DotNetInstallerUri, "$InstallPath\dotnet-install.ps1");
& $InstallPath\dotnet-install.ps1 -Channel $DotNetChannel -Version $DotNetVersion -InstallDir $InstallPath;
Remove-PathVariable "$InstallPath"
$env:PATH = "$InstallPath;$env:PATH"
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
$env:DOTNET_CLI_TELEMETRY_OPTOUT=1
}
###########################################################################
# INSTALL NUGET
###########################################################################
# Make sure nuget.exe exists.
$NugetPath = Join-Path $ToolPath "nuget.exe"
if (!(Test-Path $NugetPath)) {
Write-Host "Downloading NuGet.exe..."
(New-Object System.Net.WebClient).DownloadFile($NugetUrl, $NugetPath);
}
###########################################################################
# INSTALL CAKE
###########################################################################
# Make sure Cake has been installed.
$CakePath = Join-Path $ToolPath "Cake.$CakeVersion/Cake.exe"
if (!(Test-Path $CakePath)) {
Write-Host "Installing Cake..."
Invoke-Expression "&`"$NugetPath`" install Cake -Version $CakeVersion -OutputDirectory `"$ToolPath`"" | Out-Null;
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet addins."
Throw "An error occured while restoring Cake from NuGet."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore modules from NuGet
if (Test-Path $MODULES_PACKAGES_CONFIG) {
Push-Location
Set-Location $MODULES_DIR
###########################################################################
# RUN BUILD SCRIPT
###########################################################################
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"
}
# Build the argument list.
$Arguments = @{
target=$Target;
configuration=$Configuration;
verbosity=$Verbosity;
dryrun=$WhatIf;
}.GetEnumerator() | %{"--{0}=`"{1}`"" -f $_.key, $_.value };
# Start Cake
Write-Host "Running build script..."
Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs"
Invoke-Expression "& `"$CakePath`" `"$Script`" $Arguments $ScriptArgs"
exit $LASTEXITCODE

View File

@@ -1,42 +0,0 @@
#!/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" "$@"

3
global.json Normal file
View File

@@ -0,0 +1,3 @@
{
"projects": ["src","test"]
}

View File

@@ -61,12 +61,18 @@ namespace SharpCompress.Archives
void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry)
{
EntryExtractionBegin?.Invoke(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
if (EntryExtractionBegin != null)
{
EntryExtractionBegin(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
}
}
void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry)
{
EntryExtractionEnd?.Invoke(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
if (EntryExtractionEnd != null)
{
EntryExtractionEnd(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
}
}
private static Stream CheckStreams(Stream stream)
@@ -123,21 +129,27 @@ namespace SharpCompress.Archives
void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
{
CompressedBytesRead?.Invoke(this, new CompressedBytesReadEventArgs
if (CompressedBytesRead != null)
{
CurrentFilePartCompressedBytesRead = currentPartCompressedBytes,
CompressedBytesRead = compressedReadBytes
});
CompressedBytesRead(this, new CompressedBytesReadEventArgs
{
CurrentFilePartCompressedBytesRead = currentPartCompressedBytes,
CompressedBytesRead = compressedReadBytes
});
}
}
void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
{
FilePartExtractionBegin?.Invoke(this, new FilePartExtractionBeginEventArgs
if (FilePartExtractionBegin != null)
{
CompressedSize = compressedSize,
Size = size,
Name = name
});
FilePartExtractionBegin(this, new FilePartExtractionBeginEventArgs
{
CompressedSize = compressedSize,
Size = size,
Name = name
});
}
}
/// <summary>

View File

@@ -6,7 +6,6 @@ using SharpCompress.Archives.SevenZip;
using SharpCompress.Archives.Tar;
using SharpCompress.Archives.Zip;
using SharpCompress.Common;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Readers;
namespace SharpCompress.Archives
@@ -56,7 +55,7 @@ namespace SharpCompress.Archives
stream.Seek(0, SeekOrigin.Begin);
return TarArchive.Open(stream, readerOptions);
}
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip, LZip");
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
}
public static IWritableArchive Create(ArchiveType type)

View File

@@ -14,7 +14,6 @@ namespace SharpCompress.Archives.GZip
public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
{
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
@@ -37,7 +36,6 @@ namespace SharpCompress.Archives.GZip
return new GZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
@@ -56,11 +54,11 @@ namespace SharpCompress.Archives.GZip
#if !NO_FILE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
internal GZipArchive(FileInfo fileInfo, ReaderOptions options)
: base(ArchiveType.GZip, fileInfo, options)
{
@@ -106,9 +104,15 @@ namespace SharpCompress.Archives.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 (!stream.ReadFully(header))
if (n == 0)
{
return false;
}
if (n != 10)
{
return false;
}
@@ -154,7 +158,7 @@ namespace SharpCompress.Archives.GZip
{
throw new InvalidOperationException("Only one entry is allowed in a GZip Archive");
}
using (var writer = new GZipWriter(stream, new GZipWriterOptions(options)))
using (var writer = new GZipWriter(stream))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
@@ -175,7 +179,7 @@ namespace SharpCompress.Archives.GZip
protected override IEnumerable<GZipArchiveEntry> LoadEntries(IEnumerable<GZipVolume> volumes)
{
Stream stream = volumes.Single().Stream;
yield return new GZipArchiveEntry(this, new GZipFilePart(stream, ReaderOptions.ArchiveEncoding));
yield return new GZipArchiveEntry(this, new GZipFilePart(stream));
}
protected override IReader CreateReaderForSolidExtraction()

View File

@@ -14,12 +14,6 @@ namespace SharpCompress.Archives.GZip
public virtual Stream OpenEntryStream()
{
//this is to reset the stream to be read multiple times
var part = Parts.Single() as GZipFilePart;
if (part.GetRawStream().Position != part.EntryStartPosition)
{
part.GetRawStream().Position = part.EntryStartPosition;
}
return Parts.Single().GetCompressedStream();
}
@@ -27,7 +21,7 @@ namespace SharpCompress.Archives.GZip
public IArchive Archive { get; }
public bool IsComplete => true;
public bool IsComplete { get { return true; } }
#endregion
}

View File

@@ -22,31 +22,31 @@ namespace SharpCompress.Archives.GZip
this.closeStream = closeStream;
}
public override long Crc => 0;
public override long Crc { get { return 0; } }
public override string Key { get; }
public override long CompressedSize => 0;
public override long CompressedSize { get { return 0; } }
public override long Size { get; }
public override DateTime? LastModifiedTime { get; }
public override DateTime? CreatedTime => null;
public override DateTime? CreatedTime { get { return null; } }
public override DateTime? LastAccessedTime => null;
public override DateTime? LastAccessedTime { get { return null; } }
public override DateTime? ArchivedTime => null;
public override DateTime? ArchivedTime { get { return null; } }
public override bool IsEncrypted => false;
public override bool IsEncrypted { get { return false; } }
public override bool IsDirectory => false;
public override bool IsDirectory { get { return false; } }
public override bool IsSplit => false;
public override bool IsSplit { get { return false; } }
internal override IEnumerable<FilePart> Parts => throw new NotImplementedException();
internal override IEnumerable<FilePart> Parts { get { throw new NotImplementedException(); } }
Stream IWritableArchiveEntry.Stream => stream;
Stream IWritableArchiveEntry.Stream { get { return stream; } }
public override Stream OpenEntryStream()
{

View File

@@ -60,7 +60,7 @@ namespace SharpCompress.Archives.Rar
return RarReader.Open(stream, ReaderOptions);
}
public override bool IsSolid => Volumes.First().IsSolidArchive;
public override bool IsSolid { get { return Volumes.First().IsSolidArchive; } }
#region Creation

View File

@@ -20,13 +20,13 @@ namespace SharpCompress.Archives.Rar
this.archive = archive;
}
public override CompressionType CompressionType => CompressionType.Rar;
public override CompressionType CompressionType { get { return CompressionType.Rar; } }
public IArchive Archive => archive;
public IArchive Archive { get { return archive; } }
internal override IEnumerable<FilePart> Parts => parts.Cast<FilePart>();
internal override IEnumerable<FilePart> Parts { get { return parts.Cast<FilePart>(); } }
internal override FileHeader FileHeader => parts.First().FileHeader;
internal override FileHeader FileHeader { get { return parts.First().FileHeader; } }
public override long Crc
{

View File

@@ -28,6 +28,6 @@ namespace SharpCompress.Archives.Rar
return stream;
}
internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName;
internal override string FilePartName { get { return "Unknown Stream - File Entry: " + FileHeader.FileName; } }
}
}

View File

@@ -4,7 +4,6 @@ using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.SevenZip;
using SharpCompress.Compressors.LZMA.Utilites;
using SharpCompress.IO;
using SharpCompress.Readers;
@@ -107,7 +106,10 @@ namespace SharpCompress.Archives.SevenZip
for (int i = 0; i < database.Files.Count; i++)
{
var file = database.Files[i];
yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding));
if (!file.IsDir)
{
yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file));
}
}
}
@@ -118,7 +120,7 @@ namespace SharpCompress.Archives.SevenZip
stream.Position = 0;
var reader = new ArchiveReader();
reader.Open(stream);
database = reader.ReadDatabase(new PasswordProvider(ReaderOptions.Password));
database = reader.ReadDatabase(null);
}
}
@@ -145,7 +147,7 @@ namespace SharpCompress.Archives.SevenZip
protected override IReader CreateReaderForSolidExtraction()
{
return new SevenZipReader(ReaderOptions, this);
return new SevenZipReader(this);
}
public override bool IsSolid { get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; } }
@@ -166,13 +168,13 @@ namespace SharpCompress.Archives.SevenZip
private Stream currentStream;
private CFileItem currentItem;
internal SevenZipReader(ReaderOptions readerOptions, SevenZipArchive archive)
: base(readerOptions, ArchiveType.SevenZip)
internal SevenZipReader(SevenZipArchive archive)
: base(new ReaderOptions(), ArchiveType.SevenZip)
{
this.archive = archive;
}
public override SevenZipVolume Volume => archive.Volumes.Single();
public override SevenZipVolume Volume { get { return archive.Volumes.Single(); } }
internal override IEnumerable<SevenZipEntry> GetEntries(Stream stream)
{
@@ -191,7 +193,7 @@ namespace SharpCompress.Archives.SevenZip
}
else
{
currentStream = archive.database.GetFolderStream(stream, currentFolder, new PasswordProvider(Options.Password));
currentStream = archive.database.GetFolderStream(stream, currentFolder, null);
}
foreach (var entry in group)
{
@@ -206,21 +208,5 @@ namespace SharpCompress.Archives.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;
}
}
}
}
}

View File

@@ -18,11 +18,11 @@ namespace SharpCompress.Archives.SevenZip
public IArchive Archive { get; }
public bool IsComplete => true;
public bool IsComplete { get { return true; } }
/// <summary>
/// This is a 7Zip Anti item
/// </summary>
public bool IsAnti => FilePart.Header.IsAnti;
public bool IsAnti { get { return FilePart.Header.IsAnti; } }
}
}

View File

@@ -16,7 +16,7 @@ namespace SharpCompress.Archives.Tar
public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
{
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
@@ -39,7 +39,7 @@ namespace SharpCompress.Archives.Tar
return new TarArchive(fileInfo, readerOptions ?? new ReaderOptions());
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
@@ -52,7 +52,6 @@ namespace SharpCompress.Archives.Tar
}
#if !NO_FILE
public static bool IsTarFile(string filePath)
{
return IsTarFile(new FileInfo(filePath));
@@ -75,7 +74,7 @@ namespace SharpCompress.Archives.Tar
{
try
{
TarHeader tar = new TarHeader(new ArchiveEncoding());
TarHeader tar = new TarHeader();
tar.Read(new BinaryReader(stream));
return tar.Name.Length > 0 && Enum.IsDefined(typeof(EntryType), tar.EntryType);
}
@@ -99,6 +98,7 @@ namespace SharpCompress.Archives.Tar
protected override IEnumerable<TarVolume> LoadVolumes(FileInfo file)
{
return new TarVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
}
#endif
@@ -127,7 +127,7 @@ namespace SharpCompress.Archives.Tar
{
Stream stream = volumes.Single().Stream;
TarHeader previousHeader = null;
foreach (TarHeader header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream, ReaderOptions.ArchiveEncoding))
foreach (TarHeader header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream))
{
if (header != null)
{
@@ -152,7 +152,7 @@ namespace SharpCompress.Archives.Tar
memoryStream.Position = 0;
var bytes = memoryStream.ToArray();
header.Name = ReaderOptions.ArchiveEncoding.Decode(bytes).TrimNulls();
header.Name = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls();
}
}
@@ -182,7 +182,7 @@ namespace SharpCompress.Archives.Tar
IEnumerable<TarArchiveEntry> oldEntries,
IEnumerable<TarArchiveEntry> newEntries)
{
using (var writer = new TarWriter(stream, new TarWriterOptions(options)))
using (var writer = new TarWriter(stream, options))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))

View File

@@ -22,7 +22,7 @@ namespace SharpCompress.Archives.Tar
public IArchive Archive { get; }
public bool IsComplete => true;
public bool IsComplete { get { return true; } }
#endregion
}

View File

@@ -22,30 +22,30 @@ namespace SharpCompress.Archives.Tar
this.closeStream = closeStream;
}
public override long Crc => 0;
public override long Crc { get { return 0; } }
public override string Key { get; }
public override long CompressedSize => 0;
public override long CompressedSize { get { return 0; } }
public override long Size { get; }
public override DateTime? LastModifiedTime { get; }
public override DateTime? CreatedTime => null;
public override DateTime? CreatedTime { get { return null; } }
public override DateTime? LastAccessedTime => null;
public override DateTime? LastAccessedTime { get { return null; } }
public override DateTime? ArchivedTime => null;
public override DateTime? ArchivedTime { get { return null; } }
public override bool IsEncrypted => false;
public override bool IsEncrypted { get { return false; } }
public override bool IsDirectory => false;
public override bool IsDirectory { get { return false; } }
public override bool IsSplit => false;
public override bool IsSplit { get { return false; } }
internal override IEnumerable<FilePart> Parts => throw new NotImplementedException();
Stream IWritableArchiveEntry.Stream => stream;
internal override IEnumerable<FilePart> Parts { get { throw new NotImplementedException(); } }
Stream IWritableArchiveEntry.Stream { get { return stream; } }
public override Stream OpenEntryStream()
{

View File

@@ -24,7 +24,6 @@ namespace SharpCompress.Archives.Zip
public CompressionLevel DeflateCompressionLevel { get; set; }
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
@@ -47,7 +46,6 @@ namespace SharpCompress.Archives.Zip
return new ZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
@@ -60,7 +58,6 @@ namespace SharpCompress.Archives.Zip
}
#if !NO_FILE
public static bool IsZipFile(string filePath, string password = null)
{
return IsZipFile(new FileInfo(filePath), password);
@@ -81,7 +78,7 @@ namespace SharpCompress.Archives.Zip
public static bool IsZipFile(Stream stream, string password = null)
{
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding());
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password);
try
{
ZipHeader header =
@@ -112,7 +109,7 @@ namespace SharpCompress.Archives.Zip
internal ZipArchive(FileInfo fileInfo, ReaderOptions readerOptions)
: base(ArchiveType.Zip, fileInfo, readerOptions)
{
headerFactory = new SeekableZipHeaderFactory(readerOptions.Password, readerOptions.ArchiveEncoding);
headerFactory = new SeekableZipHeaderFactory(readerOptions.Password);
}
protected override IEnumerable<ZipVolume> LoadVolumes(FileInfo file)
@@ -134,7 +131,7 @@ namespace SharpCompress.Archives.Zip
internal ZipArchive(Stream stream, ReaderOptions readerOptions)
: base(ArchiveType.Zip, stream, readerOptions)
{
headerFactory = new SeekableZipHeaderFactory(readerOptions.Password, readerOptions.ArchiveEncoding);
headerFactory = new SeekableZipHeaderFactory(readerOptions.Password);
}
protected override IEnumerable<ZipVolume> LoadVolumes(IEnumerable<Stream> streams)
@@ -153,19 +150,19 @@ namespace SharpCompress.Archives.Zip
switch (h.ZipHeaderType)
{
case ZipHeaderType.DirectoryEntry:
{
yield return new ZipArchiveEntry(this,
new SeekableZipFilePart(headerFactory,
h as DirectoryEntryHeader,
stream));
}
{
yield return new ZipArchiveEntry(this,
new SeekableZipFilePart(headerFactory,
h as DirectoryEntryHeader,
stream));
}
break;
case ZipHeaderType.DirectoryEnd:
{
byte[] bytes = (h as DirectoryEndHeader).Comment;
volume.Comment = ReaderOptions.ArchiveEncoding.Decode(bytes);
yield break;
}
{
byte[] bytes = (h as DirectoryEndHeader).Comment;
volume.Comment = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length);
yield break;
}
}
}
}
@@ -208,7 +205,7 @@ namespace SharpCompress.Archives.Zip
{
var stream = Volumes.Single().Stream;
stream.Position = 0;
return ZipReader.Open(stream, ReaderOptions);
return ZipReader.Open(stream);
}
}
}

View File

@@ -21,10 +21,10 @@ namespace SharpCompress.Archives.Zip
public IArchive Archive { get; }
public bool IsComplete => true;
public bool IsComplete { get { return true; } }
#endregion
public string Comment => (Parts.Single() as SeekableZipFilePart).Comment;
public string Comment { get { return (Parts.Single() as SeekableZipFilePart).Comment; } }
}
}

View File

@@ -23,31 +23,31 @@ namespace SharpCompress.Archives.Zip
this.closeStream = closeStream;
}
public override long Crc => 0;
public override long Crc { get { return 0; } }
public override string Key { get; }
public override long CompressedSize => 0;
public override long CompressedSize { get { return 0; } }
public override long Size { get; }
public override DateTime? LastModifiedTime { get; }
public override DateTime? CreatedTime => null;
public override DateTime? CreatedTime { get { return null; } }
public override DateTime? LastAccessedTime => null;
public override DateTime? LastAccessedTime { get { return null; } }
public override DateTime? ArchivedTime => null;
public override DateTime? ArchivedTime { get { return null; } }
public override bool IsEncrypted => false;
public override bool IsEncrypted { get { return false; } }
public override bool IsDirectory => false;
public override bool IsDirectory { get { return false; } }
public override bool IsSplit => false;
public override bool IsSplit { get { return false; } }
internal override IEnumerable<FilePart> Parts => throw new NotImplementedException();
internal override IEnumerable<FilePart> Parts { get { throw new NotImplementedException(); } }
Stream IWritableArchiveEntry.Stream => stream;
Stream IWritableArchiveEntry.Stream { get { return stream; } }
public override Stream OpenEntryStream()
{

View File

@@ -4,22 +4,6 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("SharpCompress")]
[assembly: AssemblyProduct("SharpCompress")]
[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";
}
}
[assembly: InternalsVisibleTo("SharpCompress.Test")]
[assembly: InternalsVisibleTo("SharpCompress.Test.Portable")]
[assembly: CLSCompliant(true)]

View File

@@ -1,119 +0,0 @@
// 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

View File

@@ -1,144 +0,0 @@
// 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

View File

@@ -1,111 +0,0 @@
// 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

View File

@@ -1,38 +0,0 @@
// 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

View File

@@ -1,60 +1,23 @@
using System;
using System.Text;
using System.Text;
namespace SharpCompress.Common
{
public class ArchiveEncoding
public static class ArchiveEncoding
{
/// <summary>
/// Default encoding to use when archive format doesn't specify one.
/// </summary>
public Encoding Default { get; set; }
public static Encoding Default { get; set; }
/// <summary>
/// ArchiveEncoding used by encryption schemes which don't comply with RFC 2898.
/// Encoding used by encryption schemes which don't comply with RFC 2898.
/// </summary>
public Encoding Password { get; set; }
public static Encoding Password { get; set; }
/// <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()
static 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));
}
}
}

View File

@@ -9,6 +9,6 @@ namespace SharpCompress.Common
Item = entry;
}
public T Item { get; }
public T Item { get; private set; }
}
}

View File

@@ -12,8 +12,6 @@
BCJ,
BCJ2,
LZip,
Xz,
Unknown,
Deflate64
Unknown
}
}

View File

@@ -65,12 +65,6 @@ 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; }
@@ -81,6 +75,6 @@ namespace SharpCompress.Common
/// <summary>
/// Entry file attribute.
/// </summary>
public virtual int? Attrib => throw new NotImplementedException();
public virtual int? Attrib { get { throw new NotImplementedException(); } }
}
}

View File

@@ -44,20 +44,20 @@ namespace SharpCompress.Common
stream.Dispose();
}
public override bool CanRead => true;
public override bool CanRead { get { return true; } }
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
public override bool CanWrite => false;
public override bool CanWrite { get { return false; } }
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length => throw new NotSupportedException();
public override long Length { get { 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)
{

View File

@@ -4,17 +4,9 @@ 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; }
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace SharpCompress.Common.GZip
{
@@ -14,35 +13,35 @@ namespace SharpCompress.Common.GZip
this.filePart = filePart;
}
public override CompressionType CompressionType => CompressionType.GZip;
public override CompressionType CompressionType { get { return CompressionType.GZip; } }
public override long Crc => 0;
public override long Crc { get { return 0; } }
public override string Key => filePart.FilePartName;
public override string Key { get { return filePart.FilePartName; } }
public override long CompressedSize => 0;
public override long CompressedSize { get { return 0; } }
public override long Size => 0;
public override long Size { get { return 0; } }
public override DateTime? LastModifiedTime => filePart.DateModified;
public override DateTime? LastModifiedTime { get { return filePart.DateModified; } }
public override DateTime? CreatedTime => null;
public override DateTime? CreatedTime { get { return null; } }
public override DateTime? LastAccessedTime => null;
public override DateTime? LastAccessedTime { get { return null; } }
public override DateTime? ArchivedTime => null;
public override DateTime? ArchivedTime { get { return null; } }
public override bool IsEncrypted => false;
public override bool IsEncrypted { get { return false; } }
public override bool IsDirectory => false;
public override bool IsDirectory { get { return false; } }
public override bool IsSplit => false;
public override bool IsSplit { get { return false; } }
internal override IEnumerable<FilePart> Parts => filePart.AsEnumerable<FilePart>();
internal override IEnumerable<FilePart> Parts { get { return filePart.AsEnumerable<FilePart>(); } }
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, OptionsBase options)
internal static IEnumerable<GZipEntry> GetEntries(Stream stream)
{
yield return new GZipEntry(new GZipFilePart(stream, options.ArchiveEncoding));
yield return new GZipEntry(new GZipFilePart(stream));
}
}
}

View File

@@ -5,37 +5,32 @@ using SharpCompress.Common.Tar.Headers;
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, ArchiveEncoding archiveEncoding)
: base(archiveEncoding)
internal GZipFilePart(Stream stream)
{
ReadAndValidateGzipHeader(stream);
EntryStartPosition = stream.Position;
this._stream = stream;
this.stream = stream;
}
internal long EntryStartPosition { get; }
internal DateTime? DateModified { get; private set; }
internal override string FilePartName => _name;
internal override string FilePartName { get { return 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)
@@ -69,16 +64,15 @@ namespace SharpCompress.Common.GZip
Int16 extraLength = (Int16)(header[0] + header[1] * 256);
byte[] extra = new byte[extraLength];
if (!stream.ReadFully(extra))
n = stream.Read(extra, 0, extra.Length);
if (n != extraLength)
{
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)
{
@@ -90,7 +84,7 @@ namespace SharpCompress.Common.GZip
}
}
private string ReadZeroTerminatedString(Stream stream)
private static string ReadZeroTerminatedString(Stream stream)
{
byte[] buf1 = new byte[1];
var list = new List<byte>();
@@ -113,8 +107,8 @@ namespace SharpCompress.Common.GZip
}
}
while (!done);
byte[] buffer = list.ToArray();
return ArchiveEncoding.Decode(buffer);
byte[] a = list.ToArray();
return ArchiveEncoding.Default.GetString(a, 0, a.Length);
}
}
}

View File

@@ -18,8 +18,8 @@ namespace SharpCompress.Common.GZip
}
#endif
public override bool IsFirstVolume => true;
public override bool IsFirstVolume { get { return true; } }
public override bool IsMultiVolume => true;
public override bool IsMultiVolume { get { return true; } }
}
}

View File

@@ -1,5 +1,4 @@
namespace SharpCompress.Common
namespace SharpCompress.Common
{
public class OptionsBase
{
@@ -7,7 +6,5 @@ namespace SharpCompress.Common
/// SharpCompress will keep the supplied streams open. Default is true.
/// </summary>
public bool LeaveStreamOpen { get; set; } = true;
public ArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding();
}
}

View File

@@ -17,7 +17,7 @@ namespace SharpCompress.Common.Rar.Headers
}
}
internal ArchiveFlags ArchiveHeaderFlags => (ArchiveFlags)Flags;
internal ArchiveFlags ArchiveHeaderFlags { get { return (ArchiveFlags)Flags; } }
internal short HighPosAv { get; private set; }
@@ -25,6 +25,6 @@ namespace SharpCompress.Common.Rar.Headers
internal byte EncryptionVersion { get; private set; }
public bool HasPassword => ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD);
public bool HasPassword { get { return ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD); } }
}
}

View File

@@ -16,7 +16,7 @@ namespace SharpCompress.Common.Rar.Headers
}
}
internal EndArchiveFlags EndArchiveFlags => (EndArchiveFlags)Flags;
internal EndArchiveFlags EndArchiveFlags { get { return (EndArchiveFlags)Flags; } }
internal int? ArchiveCRC { get; private set; }

View File

@@ -1,6 +1,6 @@
using SharpCompress.IO;
using System;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar.Headers
{
@@ -52,50 +52,50 @@ namespace SharpCompress.Common.Rar.Headers
switch (HeaderType)
{
case HeaderType.FileHeader:
{
if (FileFlags.HasFlag(FileFlags.UNICODE))
{
if (FileFlags.HasFlag(FileFlags.UNICODE))
int length = 0;
while (length < fileNameBytes.Length
&& fileNameBytes[length] != 0)
{
int length = 0;
while (length < fileNameBytes.Length
&& fileNameBytes[length] != 0)
{
length++;
}
if (length != nameSize)
{
length++;
FileName = FileNameDecoder.Decode(fileNameBytes, length);
}
else
{
FileName = ArchiveEncoding.Decode(fileNameBytes);
}
length++;
}
if (length != nameSize)
{
length++;
FileName = FileNameDecoder.Decode(fileNameBytes, length);
}
else
{
FileName = ArchiveEncoding.Decode(fileNameBytes);
FileName = DecodeDefault(fileNameBytes);
}
FileName = ConvertPath(FileName, HostOS);
}
else
{
FileName = DecodeDefault(fileNameBytes);
}
FileName = ConvertPath(FileName, HostOS);
}
break;
case HeaderType.NewSubHeader:
{
int datasize = HeaderSize - NEWLHD_SIZE - nameSize;
if (FileFlags.HasFlag(FileFlags.SALT))
{
int datasize = HeaderSize - NEWLHD_SIZE - nameSize;
if (FileFlags.HasFlag(FileFlags.SALT))
{
datasize -= SALT_SIZE;
}
if (datasize > 0)
{
SubData = reader.ReadBytes(datasize);
}
if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes))
{
RecoverySectors = SubData[8] + (SubData[9] << 8)
+ (SubData[10] << 16) + (SubData[11] << 24);
}
datasize -= SALT_SIZE;
}
if (datasize > 0)
{
SubData = reader.ReadBytes(datasize);
}
if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes))
{
RecoverySectors = SubData[8] + (SubData[9] << 8)
+ (SubData[10] << 16) + (SubData[11] << 24);
}
}
break;
}
@@ -118,6 +118,12 @@ 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;
@@ -159,20 +165,31 @@ namespace SharpCompress.Common.Rar.Headers
#if NO_FILE
return path.Replace('\\', '/');
#else
if (Path.DirectorySeparatorChar == '/')
switch (os)
{
return path.Replace('\\', '/');
}
else if (Path.DirectorySeparatorChar == '\\')
{
return path.Replace('/', '\\');
case HostOS.MacOS:
case HostOS.Unix:
{
if (Path.DirectorySeparatorChar == '\\')
{
return path.Replace('/', '\\');
}
}
break;
default:
{
if (Path.DirectorySeparatorChar == '/')
{
return path.Replace('\\', '/');
}
}
break;
}
return path;
#endif
}
internal long DataStartPosition { get; set; }
internal HostOS HostOS { get; private set; }
internal uint FileCRC { get; private set; }
@@ -191,10 +208,9 @@ namespace SharpCompress.Common.Rar.Headers
internal int FileAttributes { get; private set; }
internal FileFlags FileFlags => (FileFlags)Flags;
internal FileFlags FileFlags { get { return (FileFlags)Flags; } }
internal long CompressedSize { get; private set; }
internal long UncompressedSize { get; private set; }
internal string FileName { get; private set; }

View File

@@ -18,9 +18,9 @@ namespace SharpCompress.Common.Rar.Headers
Flags == 0x1A21 &&
HeaderSize == 0x07;
// Rar5 signature: 52 61 72 21 1A 07 01 00 (not supported yet)
// Rar5 signature: 52 61 72 21 1A 07 10 00 (not supported yet)
}
internal bool OldFormat { get; private set; }
}
}
}

View File

@@ -13,7 +13,7 @@ namespace SharpCompress.Common.Rar.Headers
Mark = reader.ReadBytes(8);
}
internal uint DataSize => AdditionalSize;
internal uint DataSize { get { return AdditionalSize; } }
internal byte Version { get; private set; }
internal ushort RecSectors { get; private set; }
internal uint TotalBlocks { get; private set; }

View File

@@ -1,7 +1,5 @@
using System;
using System.IO;
using System.IO;
using SharpCompress.IO;
using System.Text;
namespace SharpCompress.Common.Rar.Headers
{
@@ -18,18 +16,16 @@ namespace SharpCompress.Common.Rar.Headers
HeaderSize = baseHeader.HeaderSize;
AdditionalSize = baseHeader.AdditionalSize;
ReadBytes = baseHeader.ReadBytes;
ArchiveEncoding = baseHeader.ArchiveEncoding;
}
internal static RarHeader Create(RarCrcBinaryReader reader, ArchiveEncoding archiveEncoding)
internal static RarHeader Create(MarkingBinaryReader reader)
{
try
{
RarHeader header = new RarHeader();
header.ArchiveEncoding = archiveEncoding;
reader.Mark();
header.ReadStartFromReader(reader);
header.ReadFromReader(reader);
header.ReadBytes += reader.CurrentReadByteCount;
return header;
@@ -40,10 +36,9 @@ namespace SharpCompress.Common.Rar.Headers
}
}
private void ReadStartFromReader(RarCrcBinaryReader reader)
protected virtual void ReadFromReader(MarkingBinaryReader reader)
{
HeadCRC = reader.ReadUInt16();
reader.ResetCrc();
HeadCRC = reader.ReadInt16();
HeaderType = (HeaderType)(reader.ReadByte() & 0xff);
Flags = reader.ReadInt16();
HeaderSize = reader.ReadInt16();
@@ -53,12 +48,7 @@ namespace SharpCompress.Common.Rar.Headers
}
}
protected virtual void ReadFromReader(MarkingBinaryReader reader)
{
throw new NotImplementedException();
}
internal T PromoteHeader<T>(RarCrcBinaryReader reader)
internal T PromoteHeader<T>(MarkingBinaryReader reader)
where T : RarHeader, new()
{
T header = new T();
@@ -75,22 +65,9 @@ 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)
{
}
@@ -100,7 +77,7 @@ namespace SharpCompress.Common.Rar.Headers
/// </summary>
protected long ReadBytes { get; private set; }
protected ushort HeadCRC { get; private set; }
protected short HeadCRC { get; private set; }
internal HeaderType HeaderType { get; private set; }
@@ -111,8 +88,6 @@ 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>

View File

@@ -117,7 +117,7 @@ namespace SharpCompress.Common.Rar.Headers
{
#if !NO_CRYPTO
var reader = new RarCryptoBinaryReader(stream, Options.Password);
if (IsEncrypted)
{
if (Options.Password == null)
@@ -129,11 +129,11 @@ namespace SharpCompress.Common.Rar.Headers
reader.InitializeAes(salt);
}
#else
var reader = new RarCrcBinaryReader(stream);
var reader = new MarkingBinaryReader(stream);
#endif
RarHeader header = RarHeader.Create(reader, Options.ArchiveEncoding);
RarHeader header = RarHeader.Create(reader);
if (header == null)
{
return null;
@@ -141,109 +141,109 @@ namespace SharpCompress.Common.Rar.Headers
switch (header.HeaderType)
{
case HeaderType.ArchiveHeader:
{
var ah = header.PromoteHeader<ArchiveHeader>(reader);
IsEncrypted = ah.HasPassword;
return ah;
}
{
var ah = header.PromoteHeader<ArchiveHeader>(reader);
IsEncrypted = ah.HasPassword;
return ah;
}
case HeaderType.MarkHeader:
{
return header.PromoteHeader<MarkHeader>(reader);
}
{
return header.PromoteHeader<MarkHeader>(reader);
}
case HeaderType.ProtectHeader:
{
ProtectHeader ph = header.PromoteHeader<ProtectHeader>(reader);
// skip the recovery record data, we do not use it.
switch (StreamingMode)
{
ProtectHeader ph = header.PromoteHeader<ProtectHeader>(reader);
// skip the recovery record data, we do not use it.
switch (StreamingMode)
case StreamingMode.Seekable:
{
case StreamingMode.Seekable:
{
reader.BaseStream.Position += ph.DataSize;
}
break;
case StreamingMode.Streaming:
{
reader.BaseStream.Skip(ph.DataSize);
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
reader.BaseStream.Position += ph.DataSize;
}
break;
case StreamingMode.Streaming:
{
reader.BaseStream.Skip(ph.DataSize);
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
return ph;
}
return ph;
}
case HeaderType.NewSubHeader:
{
FileHeader fh = header.PromoteHeader<FileHeader>(reader);
switch (StreamingMode)
{
FileHeader fh = header.PromoteHeader<FileHeader>(reader);
switch (StreamingMode)
case StreamingMode.Seekable:
{
case StreamingMode.Seekable:
{
fh.DataStartPosition = reader.BaseStream.Position;
reader.BaseStream.Position += fh.CompressedSize;
}
break;
case StreamingMode.Streaming:
{
//skip the data because it's useless?
reader.BaseStream.Skip(fh.CompressedSize);
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
fh.DataStartPosition = reader.BaseStream.Position;
reader.BaseStream.Position += fh.CompressedSize;
}
return fh;
}
case HeaderType.FileHeader:
{
FileHeader fh = header.PromoteHeader<FileHeader>(reader);
switch (StreamingMode)
break;
case StreamingMode.Streaming:
{
case StreamingMode.Seekable:
{
fh.DataStartPosition = reader.BaseStream.Position;
reader.BaseStream.Position += fh.CompressedSize;
}
break;
case StreamingMode.Streaming:
{
var ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize);
if (fh.Salt == null)
{
fh.PackedStream = ms;
}
else
{
//skip the data because it's useless?
reader.BaseStream.Skip(fh.CompressedSize);
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
}
return fh;
}
case HeaderType.FileHeader:
{
FileHeader fh = header.PromoteHeader<FileHeader>(reader);
switch (StreamingMode)
{
case StreamingMode.Seekable:
{
fh.DataStartPosition = reader.BaseStream.Position;
reader.BaseStream.Position += fh.CompressedSize;
}
break;
case StreamingMode.Streaming:
{
var ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize);
if (fh.Salt == null)
{
fh.PackedStream = ms;
}
else
{
#if !NO_CRYPTO
fh.PackedStream = new RarCryptoWrapper(ms, Options.Password, fh.Salt);
fh.PackedStream = new RarCryptoWrapper(ms, Options.Password, fh.Salt);
#else
throw new NotSupportedException("RarCrypto not supported");
#endif
}
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
}
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
return fh;
}
return fh;
}
case HeaderType.EndArchiveHeader:
{
return header.PromoteHeader<EndArchiveHeader>(reader);
}
{
return header.PromoteHeader<EndArchiveHeader>(reader);
}
default:
{
throw new InvalidFormatException("Invalid Rar Header: " + header.HeaderType);
}
{
throw new InvalidFormatException("Invalid Rar Header: " + header.HeaderType);
}
}
}
}

View File

@@ -1,40 +0,0 @@
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;
}
}
}

View File

@@ -6,13 +6,12 @@ using SharpCompress.IO;
namespace SharpCompress.Common.Rar
{
internal class RarCryptoBinaryReader : RarCrcBinaryReader
internal class RarCryptoBinaryReader : MarkingBinaryReader
{
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)
@@ -20,22 +19,6 @@ 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; }
@@ -53,7 +36,6 @@ namespace SharpCompress.Common.Rar
{
return ReadAndDecryptBytes(count);
}
this.readCount += count;
return base.ReadBytes(count);
}
@@ -68,7 +50,7 @@ namespace SharpCompress.Common.Rar
for (int i = 0; i < alignedSize / 16; i++)
{
//long ax = System.currentTimeMillis();
byte[] cipherText = base.ReadBytesNoCrc(16);
byte[] cipherText = base.ReadBytes(16);
var readBytes = rijndael.ProcessBlock(cipherText);
foreach (var readByte in readBytes)
data.Enqueue(readByte);
@@ -81,11 +63,8 @@ namespace SharpCompress.Common.Rar
for (int i = 0; i < count; i++)
{
var b = data.Dequeue();
decryptedBytes[i] = b;
UpdateCrc(b);
decryptedBytes[i] = data.Dequeue();
}
this.readCount += count;
return decryptedBytes;
}

View File

@@ -10,44 +10,44 @@ namespace SharpCompress.Common.Rar
/// <summary>
/// The File's 32 bit CRC Hash
/// </summary>
public override long Crc => FileHeader.FileCRC;
public override long Crc { get { return FileHeader.FileCRC; } }
/// <summary>
/// The path of the file internal to the Rar Archive.
/// </summary>
public override string Key => FileHeader.FileName;
public override string Key { get { return FileHeader.FileName; } }
/// <summary>
/// The entry last modified time in the archive, if recorded
/// </summary>
public override DateTime? LastModifiedTime => FileHeader.FileLastModifiedTime;
public override DateTime? LastModifiedTime { get { return FileHeader.FileLastModifiedTime; } }
/// <summary>
/// The entry create time in the archive, if recorded
/// </summary>
public override DateTime? CreatedTime => FileHeader.FileCreatedTime;
public override DateTime? CreatedTime { get { return FileHeader.FileCreatedTime; } }
/// <summary>
/// The entry last accessed time in the archive, if recorded
/// </summary>
public override DateTime? LastAccessedTime => FileHeader.FileLastAccessedTime;
public override DateTime? LastAccessedTime { get { return FileHeader.FileLastAccessedTime; } }
/// <summary>
/// The entry time whend archived, if recorded
/// </summary>
public override DateTime? ArchivedTime => FileHeader.FileArchivedTime;
public override DateTime? ArchivedTime { get { return FileHeader.FileArchivedTime; } }
/// <summary>
/// Entry is password protected and encrypted and cannot be extracted.
/// </summary>
public override bool IsEncrypted => FileHeader.FileFlags.HasFlag(FileFlags.PASSWORD);
public override bool IsEncrypted { get { return FileHeader.FileFlags.HasFlag(FileFlags.PASSWORD); } }
/// <summary>
/// Entry is password protected and encrypted and cannot be extracted.
/// </summary>
public override bool IsDirectory => FileHeader.FileFlags.HasFlag(FileFlags.DIRECTORY);
public override bool IsDirectory { get { return FileHeader.FileFlags.HasFlag(FileFlags.DIRECTORY); } }
public override bool IsSplit => FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER);
public override bool IsSplit { get { return FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER); } }
public override string ToString()
{

View File

@@ -9,15 +9,14 @@ 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; }
internal MarkHeader MarkHeader { get; private set; }
internal FileHeader FileHeader { get; }
internal FileHeader FileHeader { get; private set; }
internal override Stream GetRawStream()
{

View File

@@ -21,7 +21,7 @@ namespace SharpCompress.Common.Rar
headerFactory = new RarHeaderFactory(mode, options);
}
internal StreamingMode Mode => headerFactory.StreamingMode;
internal StreamingMode Mode { get { return headerFactory.StreamingMode; } }
internal abstract IEnumerable<RarFilePart> ReadFileParts();

View File

@@ -1,17 +1,14 @@
using System;
using SharpCompress.Readers;
namespace SharpCompress.Common
{
public class ReaderExtractionEventArgs<T> : EventArgs
{
internal ReaderExtractionEventArgs(T entry, ReaderProgress readerProgress = null)
internal ReaderExtractionEventArgs(T entry)
{
Item = entry;
ReaderProgress = readerProgress;
}
public T Item { get; }
public ReaderProgress ReaderProgress { get; }
public T Item { get; private set; }
}
}

View File

@@ -22,13 +22,6 @@ 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()
{

View File

@@ -182,7 +182,7 @@ namespace SharpCompress.Common.SevenZip
private DateTime? TranslateTime(long? time)
{
if (time.HasValue && time.Value >= 0 && time.Value <= 2650467743999999999) //maximum Windows file time 31.12.9999
if (time.HasValue)
{
return TranslateTime(time.Value);
}
@@ -1211,7 +1211,7 @@ namespace SharpCompress.Common.SevenZip
public ArchiveDatabase ReadDatabase(IPasswordProvider pass)
{
var db = new ArchiveDatabase(pass);
var db = new ArchiveDatabase();
db.Clear();
db.MajorVersion = _header[6];
@@ -1279,7 +1279,7 @@ namespace SharpCompress.Common.SevenZip
throw new InvalidOperationException();
}
var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, db.PasswordProvider);
var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, pass);
// compressed header without content is odd but ok
if (dataVector.Count == 0)
@@ -1301,7 +1301,7 @@ namespace SharpCompress.Common.SevenZip
}
}
ReadHeader(db, db.PasswordProvider);
ReadHeader(db, pass);
}
db.Fill();
return db;
@@ -1339,20 +1339,20 @@ namespace SharpCompress.Common.SevenZip
#region Stream
public override bool CanRead => true;
public override bool CanRead { get { return true; } }
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
public override bool CanWrite => false;
public override bool CanWrite { get { return false; } }
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length => throw new NotSupportedException();
public override long Length { get { 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)
{
@@ -1441,7 +1441,7 @@ namespace SharpCompress.Common.SevenZip
#endregion
}
private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex)
private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex, IPasswordProvider pw)
{
Stream s;
if (!_cachedStreams.TryGetValue(folderIndex, out s))
@@ -1456,13 +1456,13 @@ namespace SharpCompress.Common.SevenZip
}
s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo,
_db.PasswordProvider);
pw);
_cachedStreams.Add(folderIndex, s);
}
return s;
}
public Stream OpenStream(ArchiveDatabase _db, int fileIndex)
public Stream OpenStream(ArchiveDatabase _db, int fileIndex, IPasswordProvider pw)
{
int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
int numFilesInFolder = _db.NumUnpackStreamsVector[folderIndex];
@@ -1479,12 +1479,12 @@ namespace SharpCompress.Common.SevenZip
skipSize += _db.Files[firstFileIndex + i].Size;
}
Stream s = GetCachedDecoderStream(_db, folderIndex);
Stream s = GetCachedDecoderStream(_db, folderIndex, pw);
s.Position = skipSize;
return new ReadOnlySubStream(s, _db.Files[fileIndex].Size);
}
public void Extract(ArchiveDatabase _db, int[] indices)
public void Extract(ArchiveDatabase _db, int[] indices, IPasswordProvider pw)
{
int numItems;
bool allFilesMode = (indices == null);
@@ -1562,7 +1562,7 @@ namespace SharpCompress.Common.SevenZip
// TODO: If the decoding fails the last file may be extracted incompletely. Delete it?
Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(),
folderInfo, _db.PasswordProvider);
folderInfo, pw);
byte[] buffer = new byte[4 << 10];
for (;;)
{
@@ -1588,4 +1588,4 @@ namespace SharpCompress.Common.SevenZip
#endregion
}
}
}

View File

@@ -12,9 +12,9 @@ namespace SharpCompress.Common.SevenZip
public bool HasStream { get; internal set; }
public bool IsDir { get; internal set; }
public bool CrcDefined => Crc != null;
public bool CrcDefined { get { return Crc != null; } }
public bool AttribDefined => Attrib != null;
public bool AttribDefined { get { return Attrib != null; } }
public void SetAttrib(uint attrib)
{

View File

@@ -13,7 +13,7 @@ namespace SharpCompress.Common.SevenZip
internal List<long> UnpackSizes = new List<long>();
internal uint? UnpackCRC;
internal bool UnpackCRCDefined => UnpackCRC != null;
internal bool UnpackCRCDefined { get { return UnpackCRC != null; } }
public long GetUnpackSize()
{

View File

@@ -12,32 +12,32 @@ namespace SharpCompress.Common.SevenZip
internal SevenZipFilePart FilePart { get; }
public override CompressionType CompressionType => FilePart.CompressionType;
public override CompressionType CompressionType { get { return FilePart.CompressionType; } }
public override long Crc => FilePart.Header.Crc ?? 0;
public override long Crc { get { return FilePart.Header.Crc ?? 0; } }
public override string Key => FilePart.Header.Name;
public override string Key { get { return FilePart.Header.Name; } }
public override long CompressedSize => 0;
public override long CompressedSize { get { return 0; } }
public override long Size => FilePart.Header.Size;
public override long Size { get { return FilePart.Header.Size; } }
public override DateTime? LastModifiedTime => FilePart.Header.MTime;
public override DateTime? LastModifiedTime { get { return FilePart.Header.MTime; } }
public override DateTime? CreatedTime => null;
public override DateTime? CreatedTime { get { return null; } }
public override DateTime? LastAccessedTime => null;
public override DateTime? LastAccessedTime { get { return null; } }
public override DateTime? ArchivedTime => null;
public override DateTime? ArchivedTime { get { return null; } }
public override bool IsEncrypted => false;
public override bool IsEncrypted { get { return false; } }
public override bool IsDirectory => FilePart.Header.IsDir;
public override bool IsDirectory { get { return FilePart.Header.IsDir; } }
public override bool IsSplit => false;
public override bool IsSplit { get { return false; } }
public override int? Attrib => (int)FilePart.Header.Attrib;
public override int? Attrib { get { return (int)FilePart.Header.Attrib; } }
internal override IEnumerable<FilePart> Parts => FilePart.AsEnumerable<FilePart>();
internal override IEnumerable<FilePart> Parts { get { return FilePart.AsEnumerable<FilePart>(); } }
}
}

View File

@@ -7,15 +7,14 @@ namespace SharpCompress.Common.SevenZip
{
internal class SevenZipFilePart : FilePart
{
private CompressionType? _type;
private readonly Stream _stream;
private readonly ArchiveDatabase _database;
private CompressionType? type;
private readonly Stream stream;
private readonly ArchiveDatabase database;
internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry, ArchiveEncoding archiveEncoding)
: base(archiveEncoding)
internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry)
{
this._stream = stream;
this._database = database;
this.stream = stream;
this.database = database;
Index = index;
Header = fileEntry;
if (Header.HasStream)
@@ -29,7 +28,7 @@ namespace SharpCompress.Common.SevenZip
internal CFolder Folder { get; }
internal int Index { get; }
internal override string FilePartName => Header.Name;
internal override string FilePartName { get { return Header.Name; } }
internal override Stream GetRawStream()
{
@@ -42,14 +41,14 @@ namespace SharpCompress.Common.SevenZip
{
return null;
}
var folderStream = _database.GetFolderStream(_stream, Folder, _database.PasswordProvider);
var folderStream = database.GetFolderStream(stream, Folder, null);
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)
{
@@ -62,11 +61,11 @@ namespace SharpCompress.Common.SevenZip
{
get
{
if (_type == null)
if (type == null)
{
_type = GetCompression();
type = GetCompression();
}
return _type.Value;
return type.Value;
}
}
@@ -85,7 +84,7 @@ namespace SharpCompress.Common.SevenZip
{
var coder = Folder.Coders.First();
switch (coder.MethodId.Id)
{
{
case k_LZMA:
case k_LZMA2:
{

View File

@@ -9,11 +9,6 @@ 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; }
@@ -25,7 +20,6 @@ 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;
@@ -37,7 +31,7 @@ namespace SharpCompress.Common.Tar.Headers
WriteOctalBytes(0, buffer, 108, 8); // owner ID
WriteOctalBytes(0, buffer, 116, 8); // group ID
//ArchiveEncoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
//Encoding.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
@@ -78,7 +72,7 @@ namespace SharpCompress.Common.Tar.Headers
private void WriteLongFilenameHeader(Stream output)
{
byte[] nameBytes = ArchiveEncoding.Encode(Name);
byte[] nameBytes = ArchiveEncoding.Default.GetBytes(Name);
output.Write(nameBytes, 0, nameBytes.Length);
// pad to multiple of BlockSize bytes, and make sure a terminating null is added
@@ -105,7 +99,7 @@ namespace SharpCompress.Common.Tar.Headers
}
else
{
Name = ArchiveEncoding.Decode(buffer, 0, 100).TrimNulls();
Name = ArchiveEncoding.Default.GetString(buffer, 0, 100).TrimNulls();
}
EntryType = ReadEntryType(buffer);
@@ -117,12 +111,12 @@ namespace SharpCompress.Common.Tar.Headers
long unixTimeStamp = ReadASCIIInt64Base8(buffer, 136, 11);
LastModifiedTime = Epoch.AddSeconds(unixTimeStamp).ToLocalTime();
Magic = ArchiveEncoding.Decode(buffer, 257, 6).TrimNulls();
Magic = ArchiveEncoding.Default.GetString(buffer, 257, 6).TrimNulls();
if (!string.IsNullOrEmpty(Magic)
&& "ustar".Equals(Magic))
{
string namePrefix = ArchiveEncoding.Decode(buffer, 345, 157);
string namePrefix = ArchiveEncoding.Default.GetString(buffer, 345, 157);
namePrefix = namePrefix.TrimNulls();
if (!string.IsNullOrEmpty(namePrefix))
{
@@ -149,7 +143,7 @@ namespace SharpCompress.Common.Tar.Headers
{
reader.ReadBytes(remainingBytesToRead);
}
return ArchiveEncoding.Decode(nameBytes, 0, nameBytes.Length).TrimNulls();
return ArchiveEncoding.Default.GetString(nameBytes, 0, nameBytes.Length).TrimNulls();
}
private static EntryType ReadEntryType(byte[] buffer)

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
using System.Text;
namespace SharpCompress.Common.Tar
{
@@ -19,34 +18,34 @@ namespace SharpCompress.Common.Tar
public override CompressionType CompressionType { get; }
public override long Crc => 0;
public override long Crc { get { return 0; } }
public override string Key => filePart.Header.Name;
public override string Key { get { return filePart.Header.Name; } }
public override long CompressedSize => filePart.Header.Size;
public override long CompressedSize { get { return filePart.Header.Size; } }
public override long Size => filePart.Header.Size;
public override long Size { get { return filePart.Header.Size; } }
public override DateTime? LastModifiedTime => filePart.Header.LastModifiedTime;
public override DateTime? LastModifiedTime { get { return filePart.Header.LastModifiedTime; } }
public override DateTime? CreatedTime => null;
public override DateTime? CreatedTime { get { return null; } }
public override DateTime? LastAccessedTime => null;
public override DateTime? LastAccessedTime { get { return null; } }
public override DateTime? ArchivedTime => null;
public override DateTime? ArchivedTime { get { return null; } }
public override bool IsEncrypted => false;
public override bool IsEncrypted { get { return false; } }
public override bool IsDirectory => filePart.Header.EntryType == EntryType.Directory;
public override bool IsDirectory { get { return filePart.Header.EntryType == EntryType.Directory; } }
public override bool IsSplit => false;
public override bool IsSplit { get { return false; } }
internal override IEnumerable<FilePart> Parts => filePart.AsEnumerable<FilePart>();
internal override IEnumerable<FilePart> Parts { get { return filePart.AsEnumerable<FilePart>(); } }
internal static IEnumerable<TarEntry> GetEntries(StreamingMode mode, Stream stream,
CompressionType compressionType, ArchiveEncoding archiveEncoding)
CompressionType compressionType)
{
foreach (TarHeader h in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding))
foreach (TarHeader h in TarHeaderFactory.ReadHeader(mode, stream))
{
if (h != null)
{

View File

@@ -6,25 +6,24 @@ namespace SharpCompress.Common.Tar
{
internal class TarFilePart : FilePart
{
private readonly Stream _seekableStream;
private readonly Stream seekableStream;
internal TarFilePart(TarHeader header, Stream seekableStream)
: base(header.ArchiveEncoding)
{
this._seekableStream = seekableStream;
this.seekableStream = seekableStream;
Header = header;
}
internal TarHeader Header { get; }
internal override string FilePartName => Header.Name;
internal override string FilePartName { get { return Header.Name; } }
internal override Stream GetCompressedStream()
{
if (_seekableStream != null)
if (seekableStream != null)
{
_seekableStream.Position = Header.DataStartPosition.Value;
return new ReadOnlySubStream(_seekableStream, Header.Size);
seekableStream.Position = Header.DataStartPosition.Value;
return new ReadOnlySubStream(seekableStream, Header.Size);
}
return Header.PackedStream;
}

View File

@@ -2,13 +2,12 @@
using System.IO;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
using System.Text;
namespace SharpCompress.Common.Tar
{
internal static class TarHeaderFactory
{
internal static IEnumerable<TarHeader> ReadHeader(StreamingMode mode, Stream stream, ArchiveEncoding archiveEncoding)
internal static IEnumerable<TarHeader> ReadHeader(StreamingMode mode, Stream stream)
{
while (true)
{
@@ -16,8 +15,7 @@ namespace SharpCompress.Common.Tar
try
{
BinaryReader reader = new BinaryReader(stream);
header = new TarHeader(archiveEncoding);
header = new TarHeader();
if (!header.Read(reader))
{
yield break;
@@ -25,22 +23,22 @@ namespace SharpCompress.Common.Tar
switch (mode)
{
case StreamingMode.Seekable:
{
header.DataStartPosition = reader.BaseStream.Position;
{
header.DataStartPosition = reader.BaseStream.Position;
//skip to nearest 512
reader.BaseStream.Position += PadTo512(header.Size);
}
//skip to nearest 512
reader.BaseStream.Position += PadTo512(header.Size);
}
break;
case StreamingMode.Streaming:
{
header.PackedStream = new TarReadOnlySubStream(stream, header.Size);
}
{
header.PackedStream = new TarReadOnlySubStream(stream, header.Size);
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
{
throw new InvalidFormatException("Invalid StreamingMode");
}
}
}
catch

View File

@@ -42,20 +42,20 @@ namespace SharpCompress.Common.Tar
public Stream Stream { get; }
public override bool CanRead => true;
public override bool CanRead { get { return true; } }
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
public override bool CanWrite => false;
public override bool CanWrite { get { return false; } }
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length => throw new NotSupportedException();
public override long Length { get { 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)
{

View File

@@ -14,7 +14,7 @@ namespace SharpCompress.Common
ReaderOptions = readerOptions;
}
internal Stream Stream => new NonDisposingStream(actualStream);
internal Stream Stream { get { return new NonDisposingStream(actualStream); } }
protected ReaderOptions ReaderOptions { get; }
@@ -22,12 +22,12 @@ namespace SharpCompress.Common
/// RarArchive is the first volume of a multi-part archive.
/// Only Rar 3.0 format and higher
/// </summary>
public virtual bool IsFirstVolume => true;
public virtual bool IsFirstVolume { get { return true; } }
/// <summary>
/// RarArchive is part of a multi-part archive.
/// </summary>
public virtual bool IsMultiVolume => true;
public virtual bool IsMultiVolume { get { return true; } }
private bool disposed;

View File

@@ -21,6 +21,18 @@ namespace SharpCompress.Common.Zip.Headers
Comment = reader.ReadBytes(CommentLength);
}
internal override void Write(BinaryWriter writer)
{
writer.Write(VolumeNumber);
writer.Write(FirstVolumeWithDirectory);
writer.Write(TotalNumberOfEntriesInDisk);
writer.Write(TotalNumberOfEntries);
writer.Write(DirectorySize);
writer.Write(DirectoryStartOffsetRelativeToDisk);
writer.Write(CommentLength);
writer.Write(Comment);
}
public ushort VolumeNumber { get; private set; }
public ushort FirstVolumeWithDirectory { get; private set; }
@@ -36,9 +48,5 @@ namespace SharpCompress.Common.Zip.Headers
public byte[] Comment { get; private set; }
public ushort TotalNumberOfEntries { get; private set; }
public bool IsZip64 => TotalNumberOfEntriesInDisk == ushort.MaxValue
|| DirectorySize == uint.MaxValue
|| DirectoryStartOffsetRelativeToDisk == uint.MaxValue;
}
}

View File

@@ -1,13 +1,12 @@
using System;
using System.IO;
using System.IO;
using System.Linq;
namespace SharpCompress.Common.Zip.Headers
{
internal class DirectoryEntryHeader : ZipFileEntry
{
public DirectoryEntryHeader(ArchiveEncoding archiveEncoding)
: base(ZipHeaderType.DirectoryEntry, archiveEncoding)
public DirectoryEntryHeader()
: base(ZipHeaderType.DirectoryEntry)
{
}
@@ -31,10 +30,10 @@ namespace SharpCompress.Common.Zip.Headers
RelativeOffsetOfEntryHeader = reader.ReadUInt32();
byte[] name = reader.ReadBytes(nameLength);
Name = ArchiveEncoding.Decode(name);
Name = DecodeString(name);
byte[] extra = reader.ReadBytes(extraLength);
byte[] comment = reader.ReadBytes(commentLength);
Comment = ArchiveEncoding.Decode(comment);
Comment = DecodeString(comment);
LoadExtra(extra);
var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField);
@@ -42,30 +41,43 @@ namespace SharpCompress.Common.Zip.Headers
{
Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName;
}
}
var zip64ExtraData = Extra.OfType<Zip64ExtendedInformationExtraField>().FirstOrDefault();
if (zip64ExtraData != null)
{
if (CompressedSize == uint.MaxValue)
{
CompressedSize = zip64ExtraData.CompressedSize;
}
if (UncompressedSize == uint.MaxValue)
{
UncompressedSize = zip64ExtraData.UncompressedSize;
}
if (RelativeOffsetOfEntryHeader == uint.MaxValue)
{
RelativeOffsetOfEntryHeader = zip64ExtraData.RelativeOffsetOfEntryHeader;
}
}
internal override void Write(BinaryWriter writer)
{
writer.Write(Version);
writer.Write(VersionNeededToExtract);
writer.Write((ushort)Flags);
writer.Write((ushort)CompressionMethod);
writer.Write(LastModifiedTime);
writer.Write(LastModifiedDate);
writer.Write(Crc);
writer.Write(CompressedSize);
writer.Write(UncompressedSize);
byte[] nameBytes = EncodeString(Name);
writer.Write((ushort)nameBytes.Length);
//writer.Write((ushort)Extra.Length);
writer.Write((ushort)0);
writer.Write((ushort)Comment.Length);
writer.Write(DiskNumberStart);
writer.Write(InternalFileAttributes);
writer.Write(ExternalFileAttributes);
writer.Write(RelativeOffsetOfEntryHeader);
writer.Write(nameBytes);
// writer.Write(Extra);
writer.Write(Comment);
}
internal ushort Version { get; private set; }
public ushort VersionNeededToExtract { get; set; }
public long RelativeOffsetOfEntryHeader { get; set; }
public uint RelativeOffsetOfEntryHeader { get; set; }
public uint ExternalFileAttributes { get; set; }

View File

@@ -5,7 +5,6 @@ namespace SharpCompress.Common.Zip.Headers
[Flags]
internal enum HeaderFlags : ushort
{
None = 0,
Encrypted = 1, // http://www.pkware.com/documents/casestudies/APPNOTE.TXT
Bit1 = 2,
Bit2 = 4,

View File

@@ -13,5 +13,10 @@ namespace SharpCompress.Common.Zip.Headers
internal override void Read(BinaryReader reader)
{
}
internal override void Write(BinaryWriter writer)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,13 +1,12 @@
using System.IO;
using System.Linq;
using System.Text;
namespace SharpCompress.Common.Zip.Headers
{
internal class LocalEntryHeader : ZipFileEntry
{
public LocalEntryHeader(ArchiveEncoding archiveEncoding)
: base(ZipHeaderType.LocalEntry, archiveEncoding)
public LocalEntryHeader()
: base(ZipHeaderType.LocalEntry)
{
}
@@ -25,7 +24,7 @@ namespace SharpCompress.Common.Zip.Headers
ushort extraLength = reader.ReadUInt16();
byte[] name = reader.ReadBytes(nameLength);
byte[] extra = reader.ReadBytes(extraLength);
Name = ArchiveEncoding.Decode(name);
Name = DecodeString(name);
LoadExtra(extra);
var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField);
@@ -33,19 +32,29 @@ namespace SharpCompress.Common.Zip.Headers
{
Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName;
}
}
var zip64ExtraData = Extra.OfType<Zip64ExtendedInformationExtraField>().FirstOrDefault();
if (zip64ExtraData != null)
{
if (CompressedSize == uint.MaxValue)
{
CompressedSize = zip64ExtraData.CompressedSize;
}
if (UncompressedSize == uint.MaxValue)
{
UncompressedSize = zip64ExtraData.UncompressedSize;
}
}
internal override void Write(BinaryWriter writer)
{
writer.Write(Version);
writer.Write((ushort)Flags);
writer.Write((ushort)CompressionMethod);
writer.Write(LastModifiedTime);
writer.Write(LastModifiedDate);
writer.Write(Crc);
writer.Write(CompressedSize);
writer.Write(UncompressedSize);
byte[] nameBytes = EncodeString(Name);
writer.Write((ushort)nameBytes.Length);
writer.Write((ushort)0);
//if (Extra != null)
//{
// writer.Write(Extra);
//}
writer.Write(nameBytes);
}
internal ushort Version { get; private set; }

View File

@@ -1,6 +1,5 @@
using System;
using System.Text;
using SharpCompress.Converters;
namespace SharpCompress.Common.Zip.Headers
{
@@ -12,8 +11,7 @@ namespace SharpCompress.Common.Zip.Headers
// Third Party Mappings
// -Info-ZIP Unicode Path Extra Field
UnicodePathExtraField = 0x7075,
Zip64ExtendedInformationExtraField = 0x0001
UnicodePathExtraField = 0x7075
}
internal class ExtraData
@@ -25,7 +23,7 @@ namespace SharpCompress.Common.Zip.Headers
internal class ExtraUnicodePathExtraField : ExtraData
{
internal byte Version => DataBytes[0];
internal byte Version { get { return DataBytes[0]; } }
internal byte[] NameCRC32
{
@@ -49,73 +47,6 @@ namespace SharpCompress.Common.Zip.Headers
}
}
internal class Zip64ExtendedInformationExtraField : ExtraData
{
public Zip64ExtendedInformationExtraField(ExtraDataType type, ushort length, byte[] dataBytes)
{
Type = type;
Length = length;
DataBytes = dataBytes;
Process();
}
//From the spec values are only in the extradata if the standard
//value is set to 0xFFFF, but if one of the sizes are present, both are.
//Hence if length == 4 volume only
// if length == 8 offset only
// if length == 12 offset + volume
// if length == 16 sizes only
// if length == 20 sizes + volume
// if length == 24 sizes + offset
// if length == 28 everything.
//It is unclear how many of these are used in the wild.
private void Process()
{
switch (DataBytes.Length)
{
case 4:
VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 0);
return;
case 8:
RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
return;
case 12:
RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 8);
return;
case 16:
UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
return;
case 20:
UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 16);
return;
case 24:
UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 16);
return;
case 28:
UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 16);
VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 24);
return;
default:
throw new ArchiveException("Unexpected size of of Zip64 extended information extra field");
}
}
public long UncompressedSize { get; private set; }
public long CompressedSize { get; private set; }
public long RelativeOffsetOfEntryHeader { get; private set; }
public uint VolumeNumber { get; private set; }
}
internal static class LocalEntryHeaderExtraFactory
{
internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData)
@@ -129,13 +60,6 @@ namespace SharpCompress.Common.Zip.Headers
Length = length,
DataBytes = extraData
};
case ExtraDataType.Zip64ExtendedInformationExtraField:
return new Zip64ExtendedInformationExtraField
(
type,
length,
extraData
);
default:
return new ExtraData
{

View File

@@ -14,5 +14,10 @@ namespace SharpCompress.Common.Zip.Headers
{
throw new NotImplementedException();
}
internal override void Write(BinaryWriter writer)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,49 +0,0 @@
using System;
using System.IO;
namespace SharpCompress.Common.Zip.Headers
{
internal class Zip64DirectoryEndHeader : ZipHeader
{
public Zip64DirectoryEndHeader()
: base(ZipHeaderType.Zip64DirectoryEnd)
{
}
internal override void Read(BinaryReader reader)
{
SizeOfDirectoryEndRecord = (long)reader.ReadUInt64();
VersionMadeBy = reader.ReadUInt16();
VersionNeededToExtract = reader.ReadUInt16();
VolumeNumber = reader.ReadUInt32();
FirstVolumeWithDirectory = reader.ReadUInt32();
TotalNumberOfEntriesInDisk = (long)reader.ReadUInt64();
TotalNumberOfEntries = (long)reader.ReadUInt64();
DirectorySize = (long)reader.ReadUInt64();
DirectoryStartOffsetRelativeToDisk = (long)reader.ReadUInt64();
DataSector = reader.ReadBytes((int)(SizeOfDirectoryEndRecord - SizeOfFixedHeaderDataExceptSignatureAndSizeFields));
}
const int SizeOfFixedHeaderDataExceptSignatureAndSizeFields = 44;
public long SizeOfDirectoryEndRecord { get; private set; }
public ushort VersionMadeBy { get; private set; }
public ushort VersionNeededToExtract { get; private set; }
public uint VolumeNumber { get; private set; }
public uint FirstVolumeWithDirectory { get; private set; }
public long TotalNumberOfEntriesInDisk { get; private set; }
public long TotalNumberOfEntries { get; private set; }
public long DirectorySize { get; private set; }
public long DirectoryStartOffsetRelativeToDisk { get; private set; }
public byte[] DataSector { get; private set; }
}
}

View File

@@ -1,25 +0,0 @@
using System.IO;
namespace SharpCompress.Common.Zip.Headers
{
internal class Zip64DirectoryEndLocatorHeader : ZipHeader
{
public Zip64DirectoryEndLocatorHeader()
: base(ZipHeaderType.Zip64DirectoryEndLocator)
{
}
internal override void Read(BinaryReader reader)
{
FirstVolumeWithDirectory = reader.ReadUInt32();
RelativeOffsetOfTheEndOfDirectoryRecord = (long)reader.ReadUInt64();
TotalNumberOfVolumes = reader.ReadUInt32();
}
public uint FirstVolumeWithDirectory { get; private set; }
public long RelativeOffsetOfTheEndOfDirectoryRecord { get; private set; }
public uint TotalNumberOfVolumes { get; private set; }
}
}

View File

@@ -8,11 +8,10 @@ namespace SharpCompress.Common.Zip.Headers
{
internal abstract class ZipFileEntry : ZipHeader
{
protected ZipFileEntry(ZipHeaderType type, ArchiveEncoding archiveEncoding)
protected ZipFileEntry(ZipHeaderType type)
: base(type)
{
Extra = new List<ExtraData>();
ArchiveEncoding = archiveEncoding;
}
internal bool IsDirectory
@@ -30,10 +29,27 @@ namespace SharpCompress.Common.Zip.Headers
&& Name.EndsWith("\\");
}
}
internal Stream PackedStream { get; set; }
internal ArchiveEncoding ArchiveEncoding { get; }
protected string DecodeString(byte[] str)
{
if (FlagUtility.HasFlag(Flags, HeaderFlags.UTF8))
{
return Encoding.UTF8.GetString(str, 0, str.Length);
}
return ArchiveEncoding.Default.GetString(str, 0, str.Length);
}
protected byte[] EncodeString(string str)
{
if (FlagUtility.HasFlag(Flags, HeaderFlags.UTF8))
{
return Encoding.UTF8.GetBytes(str);
}
return ArchiveEncoding.Default.GetBytes(str);
}
internal Stream PackedStream { get; set; }
internal string Name { get; set; }
@@ -41,31 +57,15 @@ namespace SharpCompress.Common.Zip.Headers
internal ZipCompressionMethod CompressionMethod { get; set; }
internal long CompressedSize { get; set; }
internal uint CompressedSize { get; set; }
internal long? DataStartPosition { get; set; }
internal long UncompressedSize { get; set; }
internal uint UncompressedSize { get; set; }
internal List<ExtraData> Extra { get; set; }
public string Password { get; set; }
internal PkwareTraditionalEncryptionData ComposeEncryptionData(Stream archiveStream)
{
if (archiveStream == null)
{
throw new ArgumentNullException(nameof(archiveStream));
}
var buffer = new byte[12];
archiveStream.ReadFully(buffer);
PkwareTraditionalEncryptionData encryptionData = PkwareTraditionalEncryptionData.ForRead(Password, this, buffer);
return encryptionData;
}
internal PkwareTraditionalEncryptionData PkwareTraditionalEncryptionData { get; set; }
#if !NO_CRYPTO
internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; }
#endif
@@ -96,7 +96,5 @@ namespace SharpCompress.Common.Zip.Headers
}
internal ZipFilePart Part { get; set; }
internal bool IsZip64 => CompressedSize == uint.MaxValue;
}
}

View File

@@ -10,10 +10,12 @@ namespace SharpCompress.Common.Zip.Headers
HasData = true;
}
internal ZipHeaderType ZipHeaderType { get; }
internal ZipHeaderType ZipHeaderType { get; private set; }
internal abstract void Read(BinaryReader reader);
internal abstract void Write(BinaryWriter writer);
internal bool HasData { get; set; }
}
}

View File

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

View File

@@ -23,15 +23,15 @@ namespace SharpCompress.Common.Zip
this.mode = mode;
}
public override bool CanRead => (mode == CryptoMode.Decrypt);
public override bool CanRead { get { return (mode == CryptoMode.Decrypt); } }
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
public override bool CanWrite => (mode == CryptoMode.Encrypt);
public override bool CanWrite { get { return (mode == CryptoMode.Encrypt); } }
public override long Length => throw new NotSupportedException();
public override long Length { get { 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)
{
@@ -42,7 +42,7 @@ namespace SharpCompress.Common.Zip
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
throw new ArgumentNullException("buffer");
}
byte[] temp = new byte[count];

View File

@@ -9,12 +9,11 @@ namespace SharpCompress.Common.Zip
{
private static readonly CRC32 crc32 = new CRC32();
private readonly UInt32[] _Keys = {0x12345678, 0x23456789, 0x34567890};
private readonly ArchiveEncoding _archiveEncoding;
private readonly string password;
private PkwareTraditionalEncryptionData(string password, ArchiveEncoding archiveEncoding)
private PkwareTraditionalEncryptionData(string password)
{
_archiveEncoding = archiveEncoding;
Initialize(password);
this.password = password;
}
private byte MagicByte
@@ -29,7 +28,8 @@ namespace SharpCompress.Common.Zip
public static PkwareTraditionalEncryptionData ForRead(string password, ZipFileEntry header,
byte[] encryptionHeader)
{
var encryptor = new PkwareTraditionalEncryptionData(password, header.ArchiveEncoding);
var encryptor = new PkwareTraditionalEncryptionData(password);
encryptor.InitializeKeys();
byte[] plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length);
if (plainTextHeader[11] != (byte)((header.Crc >> 24) & 0xff))
{
@@ -49,7 +49,7 @@ namespace SharpCompress.Common.Zip
{
if (length > cipherText.Length)
{
throw new ArgumentOutOfRangeException(nameof(length),
throw new ArgumentOutOfRangeException("length",
"Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array.");
}
@@ -72,7 +72,7 @@ namespace SharpCompress.Common.Zip
if (length > plainText.Length)
{
throw new ArgumentOutOfRangeException(nameof(length),
throw new ArgumentOutOfRangeException("length",
"Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array.");
}
@@ -86,7 +86,7 @@ namespace SharpCompress.Common.Zip
return cipherText;
}
private void Initialize(string password)
internal void InitializeKeys()
{
byte[] p = StringToByteArray(password);
for (int i = 0; i < password.Length; i++)
@@ -95,12 +95,17 @@ namespace SharpCompress.Common.Zip
}
}
internal byte[] StringToByteArray(string value)
internal static byte[] StringToByteArray(string value, Encoding encoding)
{
byte[] a = _archiveEncoding.Password.GetBytes(value);
byte[] a = encoding.GetBytes(value);
return a;
}
internal static byte[] StringToByteArray(string value)
{
return StringToByteArray(value, ArchiveEncoding.Password);
}
private void UpdateKeys(byte byteValue)
{
_Keys[0] = (UInt32)crc32.ComputeCrc32((int)_Keys[0], byteValue);

View File

@@ -5,31 +5,31 @@ namespace SharpCompress.Common.Zip
{
internal class SeekableZipFilePart : ZipFilePart
{
private bool _isLocalHeaderLoaded;
private readonly SeekableZipHeaderFactory _headerFactory;
private bool isLocalHeaderLoaded;
private readonly SeekableZipHeaderFactory headerFactory;
internal SeekableZipFilePart(SeekableZipHeaderFactory headerFactory, DirectoryEntryHeader header, Stream stream)
: base(header, stream)
{
this._headerFactory = headerFactory;
this.headerFactory = headerFactory;
}
internal override Stream GetCompressedStream()
{
if (!_isLocalHeaderLoaded)
if (!isLocalHeaderLoaded)
{
LoadLocalHeader();
_isLocalHeaderLoaded = true;
isLocalHeaderLoaded = true;
}
return base.GetCompressedStream();
}
internal string Comment => (Header as DirectoryEntryHeader).Comment;
internal string Comment { get { return (Header as DirectoryEntryHeader).Comment; } }
private void LoadLocalHeader()
{
bool hasData = Header.HasData;
Header = _headerFactory.GetLocalHeader(BaseStream, Header as DirectoryEntryHeader);
Header = headerFactory.GetLocalHeader(BaseStream, Header as DirectoryEntryHeader);
Header.HasData = hasData;
}

View File

@@ -3,71 +3,24 @@ using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.IO;
using System.Text;
namespace SharpCompress.Common.Zip
{
internal class SeekableZipHeaderFactory : ZipHeaderFactory
{
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096;
private bool _zip64;
internal SeekableZipHeaderFactory(string password, ArchiveEncoding archiveEncoding)
: base(StreamingMode.Seekable, password, archiveEncoding)
internal SeekableZipHeaderFactory(string password)
: base(StreamingMode.Seekable, password)
{
}
internal IEnumerable<DirectoryEntryHeader> ReadSeekableHeader(Stream stream)
{
var reader = new BinaryReader(stream);
SeekBackToHeader(stream, reader, DIRECTORY_END_HEADER_BYTES);
var entry = new DirectoryEndHeader();
entry.Read(reader);
if (entry.IsZip64)
{
_zip64 = true;
SeekBackToHeader(stream, reader, ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR);
var zip64Locator = new Zip64DirectoryEndLocatorHeader();
zip64Locator.Read(reader);
stream.Seek(zip64Locator.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin);
uint zip64Signature = reader.ReadUInt32();
if (zip64Signature != ZIP64_END_OF_CENTRAL_DIRECTORY)
throw new ArchiveException("Failed to locate the Zip64 Header");
var zip64Entry = new Zip64DirectoryEndHeader();
zip64Entry.Read(reader);
stream.Seek(zip64Entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
}
else
{
stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
}
long position = stream.Position;
while (true)
{
stream.Position = position;
uint signature = reader.ReadUInt32();
var directoryEntryHeader = ReadHeader(signature, reader, _zip64) as DirectoryEntryHeader;
position = stream.Position;
if (directoryEntryHeader == null)
{
yield break;
}
//entry could be zero bytes so we need to know that.
directoryEntryHeader.HasData = directoryEntryHeader.CompressedSize != 0;
yield return directoryEntryHeader;
}
}
private static void SeekBackToHeader(Stream stream, BinaryReader reader, uint headerSignature)
{
long offset = 0;
uint signature;
BinaryReader reader = new BinaryReader(stream);
int iterationCount = 0;
do
{
@@ -81,10 +34,33 @@ namespace SharpCompress.Common.Zip
iterationCount++;
if (iterationCount > MAX_ITERATIONS_FOR_DIRECTORY_HEADER)
{
throw new ArchiveException("Could not find Zip file Directory at the end of the file. File may be corrupted.");
throw new ArchiveException(
"Could not find Zip file Directory at the end of the file. File may be corrupted.");
}
}
while (signature != headerSignature);
while (signature != DIRECTORY_END_HEADER_BYTES);
var entry = new DirectoryEndHeader();
entry.Read(reader);
stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
DirectoryEntryHeader directoryEntryHeader = null;
long position = stream.Position;
while (true)
{
stream.Position = position;
signature = reader.ReadUInt32();
directoryEntryHeader = ReadHeader(signature, reader) as DirectoryEntryHeader;
position = stream.Position;
if (directoryEntryHeader == null)
{
yield break;
}
//entry could be zero bytes so we need to know that.
directoryEntryHeader.HasData = directoryEntryHeader.CompressedSize != 0;
yield return directoryEntryHeader;
}
}
internal LocalEntryHeader GetLocalHeader(Stream stream, DirectoryEntryHeader directoryEntryHeader)
@@ -92,7 +68,7 @@ namespace SharpCompress.Common.Zip
stream.Seek(directoryEntryHeader.RelativeOffsetOfEntryHeader, SeekOrigin.Begin);
BinaryReader reader = new BinaryReader(stream);
uint signature = reader.ReadUInt32();
var localEntryHeader = ReadHeader(signature, reader, _zip64) as LocalEntryHeader;
var localEntryHeader = ReadHeader(signature, reader) as LocalEntryHeader;
if (localEntryHeader == null)
{
throw new InvalidOperationException();

View File

@@ -25,7 +25,7 @@ namespace SharpCompress.Common.Zip
{
return Stream.Null;
}
decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream()), Header.CompressionMethod);
decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream()));
if (LeaveStreamOpen)
{
return new NonDisposingStream(decompressionStream);
@@ -39,20 +39,19 @@ namespace SharpCompress.Common.Zip
{
return new BinaryReader(rewindableStream);
}
if (Header.HasData && !Skipped)
if (Header.HasData)
{
if (decompressionStream == null)
{
decompressionStream = GetCompressedStream();
}
decompressionStream.Skip();
decompressionStream.SkipAll();
DeflateStream deflateStream = decompressionStream as DeflateStream;
if (deflateStream != null)
{
rewindableStream.Rewind(deflateStream.InputBuffer);
}
Skipped = true;
}
var reader = new BinaryReader(rewindableStream);
decompressionStream = null;

View File

@@ -2,14 +2,13 @@
using System.IO;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.IO;
using System.Text;
namespace SharpCompress.Common.Zip
{
internal class StreamingZipHeaderFactory : ZipHeaderFactory
{
internal StreamingZipHeaderFactory(string password, ArchiveEncoding archiveEncoding)
: base(StreamingMode.Streaming, password, archiveEncoding)
internal StreamingZipHeaderFactory(string password)
: base(StreamingMode.Streaming, password)
{
}
@@ -29,7 +28,7 @@ namespace SharpCompress.Common.Zip
ZipHeader header = null;
BinaryReader reader = new BinaryReader(rewindableStream);
if (lastEntryHeader != null &&
(FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) || lastEntryHeader.IsZip64))
FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
{
reader = (lastEntryHeader.Part as StreamingZipFilePart).FixStreamedFileLocation(ref rewindableStream);
long? pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null;

View File

@@ -78,7 +78,7 @@ namespace SharpCompress.Common.Zip
{
//read out last 10 auth bytes
var ten = new byte[10];
stream.ReadFully(ten);
stream.Read(ten, 0, 10);
stream.Dispose();
}
}

View File

@@ -32,10 +32,6 @@ namespace SharpCompress.Common.Zip
{
return CompressionType.Deflate;
}
case ZipCompressionMethod.Deflate64:
{
return CompressionType.Deflate64;
}
case ZipCompressionMethod.LZMA:
{
return CompressionType.LZMA;
@@ -56,28 +52,28 @@ namespace SharpCompress.Common.Zip
}
}
public override long Crc => filePart.Header.Crc;
public override long Crc { get { return filePart.Header.Crc; } }
public override string Key => filePart.Header.Name;
public override string Key { get { return filePart.Header.Name; } }
public override long CompressedSize => filePart.Header.CompressedSize;
public override long CompressedSize { get { return filePart.Header.CompressedSize; } }
public override long Size => filePart.Header.UncompressedSize;
public override long Size { get { return filePart.Header.UncompressedSize; } }
public override DateTime? LastModifiedTime { get; }
public override DateTime? CreatedTime => null;
public override DateTime? CreatedTime { get { return null; } }
public override DateTime? LastAccessedTime => null;
public override DateTime? LastAccessedTime { get { return null; } }
public override DateTime? ArchivedTime => null;
public override DateTime? ArchivedTime { get { return null; } }
public override bool IsEncrypted => FlagUtility.HasFlag(filePart.Header.Flags, HeaderFlags.Encrypted);
public override bool IsEncrypted { get { return FlagUtility.HasFlag(filePart.Header.Flags, HeaderFlags.Encrypted); } }
public override bool IsDirectory => filePart.Header.IsDirectory;
public override bool IsDirectory { get { return filePart.Header.IsDirectory; } }
public override bool IsSplit => false;
public override bool IsSplit { get { return false; } }
internal override IEnumerable<FilePart> Parts => filePart.AsEnumerable<FilePart>();
internal override IEnumerable<FilePart> Parts { get { return filePart.AsEnumerable<FilePart>(); } }
}
}

View File

@@ -5,7 +5,6 @@ using SharpCompress.Common.Zip.Headers;
using SharpCompress.Compressors;
using SharpCompress.Compressors.BZip2;
using SharpCompress.Compressors.Deflate;
using SharpCompress.Compressors.Deflate64;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Compressors.PPMd;
using SharpCompress.Converters;
@@ -16,17 +15,16 @@ namespace SharpCompress.Common.Zip
internal abstract class ZipFilePart : FilePart
{
internal ZipFilePart(ZipFileEntry header, Stream stream)
: base(header.ArchiveEncoding)
{
Header = header;
header.Part = this;
BaseStream = stream;
}
internal Stream BaseStream { get; }
internal Stream BaseStream { get; private set; }
internal ZipFileEntry Header { get; set; }
internal override string FilePartName => Header.Name;
internal override string FilePartName { get { return Header.Name; } }
internal override Stream GetCompressedStream()
{
@@ -34,7 +32,7 @@ namespace SharpCompress.Common.Zip
{
return Stream.Null;
}
Stream decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream()), Header.CompressionMethod);
Stream decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream()));
if (LeaveStreamOpen)
{
return new NonDisposingStream(decompressionStream);
@@ -53,11 +51,11 @@ namespace SharpCompress.Common.Zip
protected abstract Stream CreateBaseStream();
protected bool LeaveStreamOpen => FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) || Header.IsZip64;
protected bool LeaveStreamOpen { get { return FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor); } }
protected Stream CreateDecompressionStream(Stream stream, ZipCompressionMethod method)
protected Stream CreateDecompressionStream(Stream stream)
{
switch (method)
switch (Header.CompressionMethod)
{
case ZipCompressionMethod.None:
{
@@ -67,10 +65,6 @@ namespace SharpCompress.Common.Zip
{
return new DeflateStream(stream, CompressionMode.Decompress);
}
case ZipCompressionMethod.Deflate64:
{
return new Deflate64Stream(stream, CompressionMode.Decompress);
}
case ZipCompressionMethod.BZip2:
{
return new BZip2Stream(stream, CompressionMode.Decompress);
@@ -94,7 +88,7 @@ namespace SharpCompress.Common.Zip
case ZipCompressionMethod.PPMd:
{
var props = new byte[2];
stream.ReadFully(props);
stream.Read(props, 0, props.Length);
return new PpmdStream(new PpmdProperties(props), stream, false);
}
case ZipCompressionMethod.WinzipAes:
@@ -108,9 +102,9 @@ namespace SharpCompress.Common.Zip
{
throw new InvalidFormatException("Winzip data length is not 7.");
}
ushort compressedMethod = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 0);
ushort method = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 0);
if (compressedMethod != 0x01 && compressedMethod != 0x02)
if (method != 0x01 && method != 0x02)
{
throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata");
}
@@ -120,7 +114,8 @@ namespace SharpCompress.Common.Zip
{
throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata");
}
return CreateDecompressionStream(stream, (ZipCompressionMethod)DataConverter.LittleEndian.GetUInt16(data.DataBytes, 5));
Header.CompressionMethod = (ZipCompressionMethod)DataConverter.LittleEndian.GetUInt16(data.DataBytes, 5);
return CreateDecompressionStream(stream);
}
default:
{
@@ -131,16 +126,18 @@ namespace SharpCompress.Common.Zip
protected Stream GetCryptoStream(Stream plainStream)
{
bool isFileEncrypted = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted);
if (Header.CompressedSize == 0 && isFileEncrypted)
if ((Header.CompressedSize == 0)
#if !NO_CRYPTO
&& ((Header.PkwareTraditionalEncryptionData != null)
|| (Header.WinzipAesEncryptionData != null)))
#else
&& (Header.PkwareTraditionalEncryptionData != null))
#endif
{
throw new NotSupportedException("Cannot encrypt file with unknown size at start.");
}
if ((Header.CompressedSize == 0
if ((Header.CompressedSize == 0)
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor))
|| Header.IsZip64)
{
plainStream = new NonDisposingStream(plainStream); //make sure AES doesn't close
}
@@ -148,39 +145,19 @@ namespace SharpCompress.Common.Zip
{
plainStream = new ReadOnlySubStream(plainStream, Header.CompressedSize); //make sure AES doesn't close
}
if (isFileEncrypted)
if (Header.PkwareTraditionalEncryptionData != null)
{
switch (Header.CompressionMethod)
{
case ZipCompressionMethod.None:
case ZipCompressionMethod.Deflate:
case ZipCompressionMethod.Deflate64:
case ZipCompressionMethod.BZip2:
case ZipCompressionMethod.LZMA:
case ZipCompressionMethod.PPMd:
{
return new PkwareTraditionalCryptoStream(plainStream, Header.ComposeEncryptionData(plainStream), CryptoMode.Decrypt);
}
case ZipCompressionMethod.WinzipAes:
{
#if !NO_FILE
if (Header.WinzipAesEncryptionData != null)
{
return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10);
}
#endif
return plainStream;
}
default:
{
throw new ArgumentOutOfRangeException();
}
}
Header.PkwareTraditionalEncryptionData.InitializeKeys();
return new PkwareTraditionalCryptoStream(plainStream, Header.PkwareTraditionalEncryptionData,
CryptoMode.Decrypt);
}
#if !NO_FILE
if (Header.WinzipAesEncryptionData != null)
{
//only read 10 less because the last ten are auth bytes
return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10);
}
#endif
return plainStream;
}
}

View File

@@ -5,7 +5,6 @@ using System.Linq;
#endif
using SharpCompress.Common.Zip.Headers;
using SharpCompress.IO;
using System.Text;
namespace SharpCompress.Common.Zip
{
@@ -18,28 +17,26 @@ namespace SharpCompress.Common.Zip
internal const uint DIGITAL_SIGNATURE = 0x05054b50;
internal const uint SPLIT_ARCHIVE_HEADER_BYTES = 0x30304b50;
internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50;
internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR = 0x07064b50;
private const uint ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50;
private const uint ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR = 0x07064b50;
protected LocalEntryHeader lastEntryHeader;
private readonly string password;
private readonly StreamingMode mode;
private readonly ArchiveEncoding archiveEncoding;
protected ZipHeaderFactory(StreamingMode mode, string password, ArchiveEncoding archiveEncoding)
protected ZipHeaderFactory(StreamingMode mode, string password)
{
this.mode = mode;
this.password = password;
this.archiveEncoding = archiveEncoding;
}
protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader, bool zip64 = false)
protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader)
{
switch (headerBytes)
{
case ENTRY_HEADER_BYTES:
{
var entryHeader = new LocalEntryHeader(archiveEncoding);
var entryHeader = new LocalEntryHeader();
entryHeader.Read(reader);
LoadHeader(entryHeader, reader.BaseStream);
@@ -48,48 +45,45 @@ namespace SharpCompress.Common.Zip
}
case DIRECTORY_START_HEADER_BYTES:
{
var entry = new DirectoryEntryHeader(archiveEncoding);
var entry = new DirectoryEntryHeader();
entry.Read(reader);
return entry;
}
case POST_DATA_DESCRIPTOR:
{
if (FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
{
if (FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
{
lastEntryHeader.Crc = reader.ReadUInt32();
lastEntryHeader.CompressedSize = zip64 ? (long)reader.ReadUInt64() : reader.ReadUInt32();
lastEntryHeader.UncompressedSize = zip64 ? (long)reader.ReadUInt64() : reader.ReadUInt32();
}
else
{
reader.ReadBytes(zip64 ? 20 : 12);
}
return null;
lastEntryHeader.Crc = reader.ReadUInt32();
lastEntryHeader.CompressedSize = reader.ReadUInt32();
lastEntryHeader.UncompressedSize = reader.ReadUInt32();
}
else
{
reader.ReadUInt32();
reader.ReadUInt32();
reader.ReadUInt32();
}
return null;
}
case DIGITAL_SIGNATURE:
return null;
case DIRECTORY_END_HEADER_BYTES:
{
var entry = new DirectoryEndHeader();
entry.Read(reader);
return entry;
}
{
var entry = new DirectoryEndHeader();
entry.Read(reader);
return entry;
}
case SPLIT_ARCHIVE_HEADER_BYTES:
{
return new SplitHeader();
}
{
return new SplitHeader();
}
case ZIP64_END_OF_CENTRAL_DIRECTORY:
{
var entry = new Zip64DirectoryEndHeader();
entry.Read(reader);
return entry;
}
case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR:
{
var entry = new Zip64DirectoryEndLocatorHeader();
entry.Read(reader);
return entry;
}
{
var entry = new IgnoreHeader(ZipHeaderType.Ignore);
entry.Read(reader);
return entry;
}
default:
throw new NotSupportedException("Unknown header: " + headerBytes);
}
@@ -117,43 +111,46 @@ namespace SharpCompress.Common.Zip
{
if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted))
{
if (!entryHeader.IsDirectory && entryHeader.CompressedSize == 0 &&
if (!entryHeader.IsDirectory &&
entryHeader.CompressedSize == 0 &&
FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
{
throw new NotSupportedException("SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner.");
throw new NotSupportedException(
"SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner.");
}
if (password == null)
{
throw new CryptographicException("No password supplied for encrypted zip.");
}
entryHeader.Password = password;
if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes)
if (entryHeader.CompressionMethod != ZipCompressionMethod.WinzipAes)
{
byte[] buffer = new byte[12];
stream.Read(buffer, 0, 12);
entryHeader.PkwareTraditionalEncryptionData = PkwareTraditionalEncryptionData.ForRead(password,
entryHeader,
buffer);
entryHeader.CompressedSize -= 12;
}
else
{
#if NO_CRYPTO
throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7.");
#else
ExtraData data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes);
if (data != null)
{
var keySize = (WinzipAesKeySize)data.DataBytes[4];
var data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes);
WinzipAesKeySize keySize = (WinzipAesKeySize) data.DataBytes[4];
var salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize) / 2];
var passwordVerifyValue = new byte[2];
stream.Read(salt, 0, salt.Length);
stream.Read(passwordVerifyValue, 0, 2);
entryHeader.WinzipAesEncryptionData =
new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue, password);
byte[] salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize)/2];
byte[] passwordVerifyValue = new byte[2];
stream.Read(salt, 0, salt.Length);
stream.Read(passwordVerifyValue, 0, 2);
entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue,
password);
entryHeader.CompressedSize -= (uint) (salt.Length + 2);
entryHeader.CompressedSize -= (uint)(salt.Length + 2);
}
#endif
}
}
if (entryHeader.IsDirectory)
{
return;
@@ -168,22 +165,20 @@ namespace SharpCompress.Common.Zip
switch (mode)
{
case StreamingMode.Seekable:
{
entryHeader.DataStartPosition = stream.Position;
stream.Position += entryHeader.CompressedSize;
break;
}
{
entryHeader.DataStartPosition = stream.Position;
stream.Position += entryHeader.CompressedSize;
}
break;
case StreamingMode.Streaming:
{
entryHeader.PackedStream = stream;
break;
}
{
entryHeader.PackedStream = stream;
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
{
throw new InvalidFormatException("Invalid StreamingMode");
}
}
//}

View File

@@ -73,15 +73,15 @@ namespace SharpCompress.Compressors.ADC
this.stream = stream;
}
public override bool CanRead => stream.CanRead;
public override bool CanRead { get { return stream.CanRead; } }
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
public override bool CanWrite => false;
public override bool CanWrite { get { return false; } }
public override long Length => throw new NotSupportedException();
public override long Length { get { throw new NotSupportedException(); } }
public override long Position { get => position; set => throw new NotSupportedException(); }
public override long Position { get { return position; } set { throw new NotSupportedException(); } }
public override void Flush()
{
@@ -105,19 +105,19 @@ namespace SharpCompress.Compressors.ADC
}
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
throw new ArgumentNullException("buffer");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
throw new ArgumentOutOfRangeException("count");
}
if (offset < buffer.GetLowerBound(0))
{
throw new ArgumentOutOfRangeException(nameof(offset));
throw new ArgumentOutOfRangeException("offset");
}
if ((offset + count) > buffer.GetLength(0))
{
throw new ArgumentOutOfRangeException(nameof(count));
throw new ArgumentOutOfRangeException("count");
}
int size = -1;

View File

@@ -48,20 +48,20 @@ namespace SharpCompress.Compressors.BZip2
public CompressionMode Mode { get; }
public override bool CanRead => stream.CanRead;
public override bool CanRead { get { return stream.CanRead; } }
public override bool CanSeek => stream.CanSeek;
public override bool CanSeek { get { return stream.CanSeek; } }
public override bool CanWrite => stream.CanWrite;
public override bool CanWrite { get { return stream.CanWrite; } }
public override void Flush()
{
stream.Flush();
}
public override long Length => stream.Length;
public override long Length { get { return stream.Length; } }
public override long Position { get => stream.Position; set => stream.Position = value; }
public override long Position { get { return stream.Position; } set { stream.Position = value; } }
public override int Read(byte[] buffer, int offset, int count)
{

View File

@@ -1092,13 +1092,13 @@ namespace SharpCompress.Compressors.BZip2
{
}
public override bool CanRead => true;
public override bool CanRead { get { return true; } }
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
public override bool CanWrite => false;
public override bool CanWrite { get { return false; } }
public override long Length => 0;
public override long Length { get { return 0; } }
public override long Position { get { return 0; } set { } }
}

View File

@@ -1956,13 +1956,13 @@ namespace SharpCompress.Compressors.BZip2
}
}
public override bool CanRead => false;
public override bool CanRead { get { return false; } }
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
public override bool CanWrite => true;
public override bool CanWrite { get { return true; } }
public override long Length => 0;
public override long Length { get { return 0; } }
public override long Position { get { return 0; } set { } }
}

View File

@@ -92,14 +92,21 @@ namespace SharpCompress.Compressors.Deflate
/// <summary>
/// Indicates the current CRC for all blocks slurped in.
/// </summary>
public Int32 Crc32Result => unchecked((Int32)(~runningCrc32Result));
public Int32 Crc32Result
{
get
{
// return one's complement of the running result
return unchecked((Int32)(~runningCrc32Result));
}
}
/// <summary>
/// Returns the CRC32 for the specified stream.
/// </summary>
/// <param name="input">The stream over which to calculate the CRC32</param>
/// <returns>the CRC32 calculation</returns>
public UInt32 GetCrc32(Stream input)
public Int32 GetCrc32(Stream input)
{
return GetCrc32AndCopy(input, null);
}
@@ -111,7 +118,7 @@ namespace SharpCompress.Compressors.Deflate
/// <param name="input">The stream over which to calculate the CRC32</param>
/// <param name="output">The stream into which to deflate the input</param>
/// <returns>the CRC32 calculation</returns>
public UInt32 GetCrc32AndCopy(Stream input, Stream output)
public Int32 GetCrc32AndCopy(Stream input, Stream output)
{
if (input == null)
{
@@ -143,7 +150,7 @@ namespace SharpCompress.Compressors.Deflate
TotalBytesRead += count;
}
return ~runningCrc32Result;
return (Int32)(~runningCrc32Result);
}
}

View File

@@ -26,7 +26,6 @@
using System;
using System.IO;
using System.Text;
namespace SharpCompress.Compressors.Deflate
{
@@ -37,10 +36,9 @@ namespace SharpCompress.Compressors.Deflate
public DeflateStream(Stream stream, CompressionMode mode,
CompressionLevel level = CompressionLevel.Default,
bool leaveOpen = false,
Encoding forceEncoding = null)
bool leaveOpen = false)
{
_baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, leaveOpen, forceEncoding);
_baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, leaveOpen);
}
#region Zlib properties
@@ -52,7 +50,7 @@ namespace SharpCompress.Compressors.Deflate
/// </remarks>
public virtual FlushType FlushMode
{
get => (_baseStream._flushMode);
get { return (_baseStream._flushMode); }
set
{
if (_disposed)
@@ -82,7 +80,7 @@ namespace SharpCompress.Compressors.Deflate
/// </remarks>
public int BufferSize
{
get => _baseStream._bufferSize;
get { return _baseStream._bufferSize; }
set
{
if (_disposed)
@@ -113,7 +111,7 @@ namespace SharpCompress.Compressors.Deflate
/// </remarks>
public CompressionStrategy Strategy
{
get => _baseStream.Strategy;
get { return _baseStream.Strategy; }
set
{
if (_disposed)
@@ -125,10 +123,10 @@ namespace SharpCompress.Compressors.Deflate
}
/// <summary> Returns the total number of bytes input so far.</summary>
public virtual long TotalIn => _baseStream._z.TotalBytesIn;
public virtual long TotalIn { get { return _baseStream._z.TotalBytesIn; } }
/// <summary> Returns the total number of bytes output so far.</summary>
public virtual long TotalOut => _baseStream._z.TotalBytesOut;
public virtual long TotalOut { get { return _baseStream._z.TotalBytesOut; } }
#endregion
@@ -158,7 +156,7 @@ namespace SharpCompress.Compressors.Deflate
/// <remarks>
/// Always returns false.
/// </remarks>
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
/// <summary>
/// Indicates whether the stream can be written.
@@ -181,7 +179,7 @@ namespace SharpCompress.Compressors.Deflate
/// <summary>
/// Reading this property always throws a <see cref="NotImplementedException"/>.
/// </summary>
public override long Length => throw new NotSupportedException();
public override long Length { get { throw new NotSupportedException(); } }
/// <summary>
/// The position of the stream pointer.
@@ -208,7 +206,7 @@ namespace SharpCompress.Compressors.Deflate
}
return 0;
}
set => throw new NotSupportedException();
set { throw new NotSupportedException(); }
}
/// <summary>
@@ -344,7 +342,13 @@ namespace SharpCompress.Compressors.Deflate
#endregion
public MemoryStream InputBuffer => new MemoryStream(_baseStream._z.InputBuffer, _baseStream._z.NextIn,
_baseStream._z.AvailableBytesIn);
public MemoryStream InputBuffer
{
get
{
return new MemoryStream(_baseStream._z.InputBuffer, _baseStream._z.NextIn,
_baseStream._z.AvailableBytesIn);
}
}
}
}

View File

@@ -30,55 +30,51 @@ using System;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Converters;
using System.Text;
namespace SharpCompress.Compressors.Deflate
{
public class GZipStream : Stream
{
internal static readonly DateTime UNIX_EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public DateTime? LastModified { get; set; }
private string _comment;
private string _fileName;
private string comment;
private string fileName;
internal ZlibBaseStream BaseStream;
private bool _disposed;
private bool _firstReadDone;
private int _headerByteCount;
private readonly Encoding _encoding;
private bool disposed;
private bool firstReadDone;
private int headerByteCount;
public GZipStream(Stream stream, CompressionMode mode)
: this(stream, mode, CompressionLevel.Default, false, Encoding.UTF8)
: this(stream, mode, CompressionLevel.Default, false)
{
}
public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level)
: this(stream, mode, level, false, Encoding.UTF8)
: this(stream, mode, level, false)
{
}
public GZipStream(Stream stream, CompressionMode mode, bool leaveOpen)
: this(stream, mode, CompressionLevel.Default, leaveOpen, Encoding.UTF8)
: this(stream, mode, CompressionLevel.Default, leaveOpen)
{
}
public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen, Encoding encoding)
public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen)
{
BaseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, leaveOpen, encoding);
_encoding = encoding;
BaseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, leaveOpen);
}
#region Zlib properties
public virtual FlushType FlushMode
{
get => (BaseStream._flushMode);
get { return (BaseStream._flushMode); }
set
{
if (_disposed)
if (disposed)
{
throw new ObjectDisposedException("GZipStream");
}
@@ -88,10 +84,10 @@ namespace SharpCompress.Compressors.Deflate
public int BufferSize
{
get => BaseStream._bufferSize;
get { return BaseStream._bufferSize; }
set
{
if (_disposed)
if (disposed)
{
throw new ObjectDisposedException("GZipStream");
}
@@ -109,9 +105,9 @@ namespace SharpCompress.Compressors.Deflate
}
}
internal virtual long TotalIn => BaseStream._z.TotalBytesIn;
internal virtual long TotalIn { get { return BaseStream._z.TotalBytesIn; } }
internal virtual long TotalOut => BaseStream._z.TotalBytesOut;
internal virtual long TotalOut { get { return BaseStream._z.TotalBytesOut; } }
#endregion
@@ -127,7 +123,7 @@ namespace SharpCompress.Compressors.Deflate
{
get
{
if (_disposed)
if (disposed)
{
throw new ObjectDisposedException("GZipStream");
}
@@ -141,7 +137,7 @@ namespace SharpCompress.Compressors.Deflate
/// <remarks>
/// Always returns false.
/// </remarks>
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
/// <summary>
/// Indicates whether the stream can be written.
@@ -153,7 +149,7 @@ namespace SharpCompress.Compressors.Deflate
{
get
{
if (_disposed)
if (disposed)
{
throw new ObjectDisposedException("GZipStream");
}
@@ -164,7 +160,7 @@ namespace SharpCompress.Compressors.Deflate
/// <summary>
/// Reading this property always throws a <see cref="NotImplementedException"/>.
/// </summary>
public override long Length => throw new NotSupportedException();
public override long Length { get { throw new NotSupportedException(); } }
/// <summary>
/// The position of the stream pointer.
@@ -183,7 +179,7 @@ namespace SharpCompress.Compressors.Deflate
{
if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Writer)
{
return BaseStream._z.TotalBytesOut + _headerByteCount;
return BaseStream._z.TotalBytesOut + headerByteCount;
}
if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Reader)
{
@@ -192,7 +188,7 @@ namespace SharpCompress.Compressors.Deflate
return 0;
}
set => throw new NotSupportedException();
set { throw new NotSupportedException(); }
}
/// <summary>
@@ -206,14 +202,14 @@ namespace SharpCompress.Compressors.Deflate
{
try
{
if (!_disposed)
if (!disposed)
{
if (disposing && (BaseStream != null))
{
BaseStream.Dispose();
Crc32 = BaseStream.Crc32;
}
_disposed = true;
disposed = true;
}
}
finally
@@ -227,7 +223,7 @@ namespace SharpCompress.Compressors.Deflate
/// </summary>
public override void Flush()
{
if (_disposed)
if (disposed)
{
throw new ObjectDisposedException("GZipStream");
}
@@ -267,7 +263,7 @@ namespace SharpCompress.Compressors.Deflate
/// <returns>the number of bytes actually read</returns>
public override int Read(byte[] buffer, int offset, int count)
{
if (_disposed)
if (disposed)
{
throw new ObjectDisposedException("GZipStream");
}
@@ -276,9 +272,9 @@ namespace SharpCompress.Compressors.Deflate
// Console.WriteLine("GZipStream::Read(buffer, off({0}), c({1}) = {2}", offset, count, n);
// Console.WriteLine( Util.FormatByteArray(buffer, offset, n) );
if (!_firstReadDone)
if (!firstReadDone)
{
_firstReadDone = true;
firstReadDone = true;
FileName = BaseStream._GzipFileName;
Comment = BaseStream._GzipComment;
}
@@ -329,7 +325,7 @@ namespace SharpCompress.Compressors.Deflate
/// <param name="count">the number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
if (_disposed)
if (disposed)
{
throw new ObjectDisposedException("GZipStream");
}
@@ -339,7 +335,7 @@ namespace SharpCompress.Compressors.Deflate
if (BaseStream._wantCompress)
{
// first write in compression, therefore, emit the GZIP header
_headerByteCount = EmitHeader();
headerByteCount = EmitHeader();
}
else
{
@@ -350,56 +346,56 @@ namespace SharpCompress.Compressors.Deflate
BaseStream.Write(buffer, offset, count);
}
#endregion Stream methods
#endregion
public String Comment
{
get => _comment;
get { return comment; }
set
{
if (_disposed)
if (disposed)
{
throw new ObjectDisposedException("GZipStream");
}
_comment = value;
comment = value;
}
}
public string FileName
{
get => _fileName;
get { return fileName; }
set
{
if (_disposed)
if (disposed)
{
throw new ObjectDisposedException("GZipStream");
}
_fileName = value;
if (_fileName == null)
fileName = value;
if (fileName == null)
{
return;
}
if (_fileName.IndexOf("/") != -1)
if (fileName.IndexOf("/") != -1)
{
_fileName = _fileName.Replace("/", "\\");
fileName = fileName.Replace("/", "\\");
}
if (_fileName.EndsWith("\\"))
if (fileName.EndsWith("\\"))
{
throw new InvalidOperationException("Illegal filename");
}
var index = _fileName.IndexOf("\\");
var index = fileName.IndexOf("\\");
if (index != -1)
{
// trim any leading path
int length = _fileName.Length;
int length = fileName.Length;
int num = length;
while (--num >= 0)
{
char c = _fileName[num];
char c = fileName[num];
if (c == '\\')
{
_fileName = _fileName.Substring(num + 1, length - num - 1);
fileName = fileName.Substring(num + 1, length - num - 1);
}
}
}
@@ -410,10 +406,8 @@ namespace SharpCompress.Compressors.Deflate
private int EmitHeader()
{
byte[] commentBytes = (Comment == null) ? null
: _encoding.GetBytes(Comment);
byte[] filenameBytes = (FileName == null) ? null
: _encoding.GetBytes(FileName);
byte[] commentBytes = (Comment == null) ? null : ArchiveEncoding.Default.GetBytes(Comment);
byte[] filenameBytes = (FileName == null) ? null : ArchiveEncoding.Default.GetBytes(FileName);
int cbLength = (Comment == null) ? 0 : commentBytes.Length + 1;
int fnLength = (FileName == null) ? 0 : filenameBytes.Length + 1;
@@ -446,7 +440,7 @@ namespace SharpCompress.Compressors.Deflate
{
LastModified = DateTime.Now;
}
TimeSpan delta = LastModified.Value - UNIX_EPOCH;
TimeSpan delta = LastModified.Value - UnixEpoch;
var timet = (Int32)delta.TotalSeconds;
DataConverter.LittleEndian.PutBytes(header, i, timet);
i += 4;

View File

@@ -418,7 +418,7 @@ namespace SharpCompress.Compressors.Deflate
internal sealed class Adler
{
// largest prime smaller than 65536
private static readonly uint BASE = 65521U;
private static readonly int BASE = 65521;
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
private static readonly int NMAX = 5552;
@@ -430,8 +430,8 @@ namespace SharpCompress.Compressors.Deflate
return 1;
}
uint s1 = adler & 0xffffU;
uint s2 = (adler >> 16) & 0xffffU;
int s1 = (int)(adler & 0xffff);
int s2 = (int)((adler >> 16) & 0xffff);
while (len > 0)
{
@@ -486,7 +486,7 @@ namespace SharpCompress.Compressors.Deflate
s1 %= BASE;
s2 %= BASE;
}
return (s2 << 16) | s1;
return (uint)((s2 << 16) | s1);
}
}
}

Some files were not shown because too many files have changed in this diff Show More