Compare commits

..

1 Commits

252 changed files with 1871 additions and 4731 deletions

2
.gitignore vendored
View File

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

View File

@@ -1,10 +0,0 @@
dist: trusty
language: csharp
solution: SharpCompress.sln
matrix:
include:
- dotnet: 1.0.4
mono: none
env: DOTNETCORE=1
script:
- ./build.sh

View File

@@ -1,13 +1,11 @@
# Archive Formats
## Accessing Archives
Archive classes allow random access to a seekable stream.
Reader classes allow forward-only reading
Writer classes allow forward-only Writing
## Supported Format Table
| Archive Format | Compression Format(s) | Compress/Decompress | Archive API | Reader API | Writer API |
| --- | --- | --- | --- | --- | --- |
| Rar | Rar | Decompress (1) | RarArchive | RarReader | N/A |
@@ -17,12 +15,11 @@ Writer classes allow forward-only Writing
| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | N/A | N/A |
1. SOLID Rars are only supported in the RarReader API.
2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported. Zip64 reading is supported.
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
## Compressors
For those who want to directly compress/decompress bits
| Compressor | Compress/Decompress |

View File

@@ -1,15 +1,11 @@
# 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)
Travis CI Build -
[![Build Status](https://travis-ci.org/adamhathcock/sharpcompress.svg?branch=master)](https://travis-ci.org/adamhathcock/sharpcompress)
## Need Help?
Post Issues on Github!
@@ -29,43 +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.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)
@@ -152,6 +117,8 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
* Embedded some BouncyCastle crypto classes to allow RAR Decryption and Winzip AES Decryption in Portable and Windows Store DLLs
* Built in Release (I think)
Some Help/Discussion: https://sharpcompress.codeplex.com/discussions
7Zip implementation based on: https://code.google.com/p/managed-lzma/
LICENSE

View File

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

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,93 +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"
};
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
settings.Framework = "netcoreapp1.1";
DotNetCoreBuild("./tests/SharpCompress.Test/SharpCompress.Test.csproj", settings);
}
Information("Building: {0} on Framework: {1}", project, framework);
Information("========");
settings.Framework = framework;
DotNetCoreBuild(project, settings);
}
}
});
Task("Test")
.IsDependentOn("Build")
.Does(() =>
{
if (!bool.Parse(EnvironmentVariable("APPVEYOR") ?? "false")
&& !bool.Parse(EnvironmentVariable("TRAVIS") ?? "false"))
.Does(() =>
{
var settings = new DotNetCoreTestSettings
{
var files = GetFiles("tests/**/*.csproj");
foreach(var file in files)
{
var settings = new DotNetCoreTestSettings
{
Configuration = "Release"
};
DotNetCoreTest(file.ToString(), settings);
}
}
else
{
Information("Skipping tests as this is AppVeyor or Travis CI");
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.19.1
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

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

@@ -106,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));
if (!file.IsDir)
{
yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file));
}
}
}
@@ -171,7 +174,7 @@ namespace SharpCompress.Archives.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)
{
@@ -206,4 +209,4 @@ namespace SharpCompress.Archives.SevenZip
}
}
}
}
}

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

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Tar;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
using SharpCompress.Readers;
using SharpCompress.Readers.Tar;
@@ -73,9 +74,9 @@ namespace SharpCompress.Archives.Tar
{
try
{
var input = new TarInputStream(stream);
var header = input.GetNextEntry();
return header.Name.Length > 0;
TarHeader tar = new TarHeader();
tar.Read(new BinaryReader(stream));
return tar.Name.Length > 0 && Enum.IsDefined(typeof(EntryType), tar.EntryType);
}
catch
{
@@ -130,7 +131,7 @@ namespace SharpCompress.Archives.Tar
{
if (header != null)
{
if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME)
if (header.EntryType == EntryType.LongName)
{
previousHeader = header;
}

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

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

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

View File

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

@@ -13,31 +13,31 @@ 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)
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.Compressors;
using SharpCompress.Compressors.Deflate;
using SharpCompress.Converters;
@@ -15,15 +16,12 @@ namespace SharpCompress.Common.GZip
internal GZipFilePart(Stream stream)
{
ReadAndValidateGzipHeader(stream);
EntryStartPosition = stream.Position;
this.stream = stream;
}
internal long EntryStartPosition { get; }
internal DateTime? DateModified { get; private set; }
internal override string FilePartName => name;
internal override string FilePartName { get { return name; } }
internal override Stream GetCompressedStream()
{

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

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

@@ -165,13 +165,25 @@ 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
@@ -196,7 +208,7 @@ 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; }

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,5 +1,4 @@
using System;
using System.IO;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar.Headers
@@ -19,14 +18,14 @@ namespace SharpCompress.Common.Rar.Headers
ReadBytes = baseHeader.ReadBytes;
}
internal static RarHeader Create(RarCrcBinaryReader reader)
internal static RarHeader Create(MarkingBinaryReader reader)
{
try
{
RarHeader header = new RarHeader();
reader.Mark();
header.ReadStartFromReader(reader);
header.ReadFromReader(reader);
header.ReadBytes += reader.CurrentReadByteCount;
return header;
@@ -37,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();
@@ -50,11 +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();
@@ -71,21 +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)
{
}
@@ -95,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; }

View File

@@ -129,7 +129,7 @@ namespace SharpCompress.Common.Rar.Headers
reader.InitializeAes(salt);
}
#else
var reader = new RarCrcBinaryReader(stream);
var reader = new MarkingBinaryReader(stream);
#endif
@@ -247,4 +247,4 @@ namespace SharpCompress.Common.Rar.Headers
}
}
}
}
}

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

@@ -14,9 +14,9 @@ namespace SharpCompress.Common.Rar
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

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

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

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

View File

@@ -0,0 +1,19 @@
namespace SharpCompress.Common.Tar.Headers
{
internal enum EntryType : byte
{
File = 0,
OldFile = (byte)'0',
HardLink = (byte)'1',
SymLink = (byte)'2',
CharDevice = (byte)'3',
BlockDevice = (byte)'4',
Directory = (byte)'5',
Fifo = (byte)'6',
LongLink = (byte)'K',
LongName = (byte)'L',
SparseFile = (byte)'S',
VolumeHeader = (byte)'V',
GlobalExtendedHeader = (byte)'g'
}
}

View File

@@ -0,0 +1,269 @@
using System;
using System.IO;
using System.Text;
using SharpCompress.Converters;
namespace SharpCompress.Common.Tar.Headers
{
internal class TarHeader
{
internal static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
internal string Name { get; set; }
//internal int Mode { get; set; }
//internal int UserId { get; set; }
//internal string UserName { get; set; }
//internal int GroupId { get; set; }
//internal string GroupName { get; set; }
internal long Size { get; set; }
internal DateTime LastModifiedTime { get; set; }
internal EntryType EntryType { get; set; }
internal Stream PackedStream { get; set; }
internal const int BlockSize = 512;
internal void Write(Stream output)
{
byte[] buffer = new byte[BlockSize];
WriteOctalBytes(511, buffer, 100, 8); // file mode
WriteOctalBytes(0, buffer, 108, 8); // owner ID
WriteOctalBytes(0, buffer, 116, 8); // group ID
//Encoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
if (Name.Length > 100)
{
// Set mock filename and filetype to indicate the next block is the actual name of the file
WriteStringBytes("././@LongLink", buffer, 0, 100);
buffer[156] = (byte)EntryType.LongName;
WriteOctalBytes(Name.Length + 1, buffer, 124, 12);
}
else
{
WriteStringBytes(Name, buffer, 0, 100);
WriteOctalBytes(Size, buffer, 124, 12);
var time = (long)(LastModifiedTime.ToUniversalTime() - Epoch).TotalSeconds;
WriteOctalBytes(time, buffer, 136, 12);
buffer[156] = (byte)EntryType;
if (Size >= 0x1FFFFFFFF)
{
byte[] bytes = DataConverter.BigEndian.GetBytes(Size);
var bytes12 = new byte[12];
bytes.CopyTo(bytes12, 12 - bytes.Length);
bytes12[0] |= 0x80;
bytes12.CopyTo(buffer, 124);
}
}
int crc = RecalculateChecksum(buffer);
WriteOctalBytes(crc, buffer, 148, 8);
output.Write(buffer, 0, buffer.Length);
if (Name.Length > 100)
{
WriteLongFilenameHeader(output);
Name = Name.Substring(0, 100);
Write(output);
}
}
private void WriteLongFilenameHeader(Stream output)
{
byte[] nameBytes = ArchiveEncoding.Default.GetBytes(Name);
output.Write(nameBytes, 0, nameBytes.Length);
// pad to multiple of BlockSize bytes, and make sure a terminating null is added
int numPaddingBytes = BlockSize - (nameBytes.Length % BlockSize);
if (numPaddingBytes == 0)
{
numPaddingBytes = BlockSize;
}
output.Write(new byte[numPaddingBytes], 0, numPaddingBytes);
}
internal bool Read(BinaryReader reader)
{
var buffer = ReadBlock(reader);
if (buffer.Length == 0)
{
return false;
}
if (ReadEntryType(buffer) == EntryType.LongName)
{
Name = ReadLongName(reader, buffer);
buffer = ReadBlock(reader);
}
else
{
Name = ArchiveEncoding.Default.GetString(buffer, 0, 100).TrimNulls();
}
EntryType = ReadEntryType(buffer);
Size = ReadSize(buffer);
//Mode = ReadASCIIInt32Base8(buffer, 100, 7);
//UserId = ReadASCIIInt32Base8(buffer, 108, 7);
//GroupId = ReadASCIIInt32Base8(buffer, 116, 7);
long unixTimeStamp = ReadASCIIInt64Base8(buffer, 136, 11);
LastModifiedTime = Epoch.AddSeconds(unixTimeStamp).ToLocalTime();
Magic = ArchiveEncoding.Default.GetString(buffer, 257, 6).TrimNulls();
if (!string.IsNullOrEmpty(Magic)
&& "ustar".Equals(Magic))
{
string namePrefix = ArchiveEncoding.Default.GetString(buffer, 345, 157);
namePrefix = namePrefix.TrimNulls();
if (!string.IsNullOrEmpty(namePrefix))
{
Name = namePrefix + "/" + Name;
}
}
if (EntryType != EntryType.LongName
&& Name.Length == 0)
{
return false;
}
return true;
}
private string ReadLongName(BinaryReader reader, byte[] buffer)
{
var size = ReadSize(buffer);
var nameLength = (int)size;
var nameBytes = reader.ReadBytes(nameLength);
var remainingBytesToRead = BlockSize - (nameLength % BlockSize);
// Read the rest of the block and discard the data
if (remainingBytesToRead < BlockSize)
{
reader.ReadBytes(remainingBytesToRead);
}
return ArchiveEncoding.Default.GetString(nameBytes, 0, nameBytes.Length).TrimNulls();
}
private static EntryType ReadEntryType(byte[] buffer)
{
return (EntryType)buffer[156];
}
private long ReadSize(byte[] buffer)
{
if ((buffer[124] & 0x80) == 0x80) // if size in binary
{
return DataConverter.BigEndian.GetInt64(buffer, 0x80);
}
return ReadASCIIInt64Base8(buffer, 124, 11);
}
private static byte[] ReadBlock(BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(BlockSize);
if (buffer.Length != 0 && buffer.Length < BlockSize)
{
throw new InvalidOperationException("Buffer is invalid size");
}
return buffer;
}
private static void WriteStringBytes(string name, byte[] buffer, int offset, int length)
{
int i;
for (i = 0; i < length - 1 && i < name.Length; ++i)
{
buffer[offset + i] = (byte)name[i];
}
for (; i < length; ++i)
{
buffer[offset + i] = 0;
}
}
private static void WriteOctalBytes(long value, byte[] buffer, int offset, int length)
{
string val = Convert.ToString(value, 8);
int shift = length - val.Length - 1;
for (int i = 0; i < shift; i++)
{
buffer[offset + i] = (byte)' ';
}
for (int i = 0; i < val.Length; i++)
{
buffer[offset + i + shift] = (byte)val[i];
}
}
private static int ReadASCIIInt32Base8(byte[] buffer, int offset, int count)
{
string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls();
if (string.IsNullOrEmpty(s))
{
return 0;
}
return Convert.ToInt32(s, 8);
}
private static long ReadASCIIInt64Base8(byte[] buffer, int offset, int count)
{
string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls();
if (string.IsNullOrEmpty(s))
{
return 0;
}
return Convert.ToInt64(s, 8);
}
private static long ReadASCIIInt64(byte[] buffer, int offset, int count)
{
string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls();
if (string.IsNullOrEmpty(s))
{
return 0;
}
return Convert.ToInt64(s);
}
internal static int RecalculateChecksum(byte[] buf)
{
// Set default value for checksum. That is 8 spaces.
Encoding.UTF8.GetBytes(" ").CopyTo(buf, 148);
// Calculate checksum
int headerChecksum = 0;
foreach (byte b in buf)
{
headerChecksum += b;
}
return headerChecksum;
}
internal static int RecalculateAltChecksum(byte[] buf)
{
Encoding.UTF8.GetBytes(" ").CopyTo(buf, 148);
int headerChecksum = 0;
foreach (byte b in buf)
{
if ((b & 0x80) == 0x80)
{
headerChecksum -= b ^ 0x80;
}
else
{
headerChecksum += b;
}
}
return headerChecksum;
}
public long? DataStartPosition { get; set; }
public string Magic { get; set; }
}
}

View File

@@ -1,541 +0,0 @@
using System;
using System.IO;
namespace SharpCompress.Common.Tar
{
/// <summary>
/// The TarBuffer class implements the tar archive concept
/// of a buffered input stream. This concept goes back to the
/// days of blocked tape drives and special io devices. In the
/// C# universe, the only real function that this class
/// performs is to ensure that files have the correct "record"
/// size, or other tars will complain.
/// <p>
/// You should never have a need to access this class directly.
/// TarBuffers are created by Tar IO Streams.
/// </p>
/// </summary>
public class TarBuffer
{
/* A quote from GNU tar man file on blocking and records
A `tar' archive file contains a series of blocks. Each block
contains `BLOCKSIZE' bytes. Although this format may be thought of as
being on magnetic tape, other media are often used.
Each file archived is represented by a header block which describes
the file, followed by zero or more blocks which give the contents of
the file. At the end of the archive file there may be a block filled
with binary zeros as an end-of-file marker. A reasonable system should
write a block of zeros at the end, but must not assume that such a
block exists when reading an archive.
The blocks may be "blocked" for physical I/O operations. Each
record of N blocks is written with a single 'write ()'
operation. On magnetic tapes, the result of such a write is a single
record. When writing an archive, the last record of blocks should be
written at the full size, with blocks after the zero block containing
all zeros. When reading an archive, a reasonable system should
properly handle an archive whose last record is shorter than the rest,
or which contains garbage records after a zero block.
*/
#region Constants
/// <summary>
/// The size of a block in a tar archive in bytes.
/// </summary>
/// <remarks>This is 512 bytes.</remarks>
public const int BlockSize = 512;
/// <summary>
/// The number of blocks in a default record.
/// </summary>
/// <remarks>
/// The default value is 20 blocks per record.
/// </remarks>
public const int DefaultBlockFactor = 20;
/// <summary>
/// The size in bytes of a default record.
/// </summary>
/// <remarks>
/// The default size is 10KB.
/// </remarks>
public const int DefaultRecordSize = BlockSize * DefaultBlockFactor;
#endregion
/// <summary>
/// Get the record size for this buffer
/// </summary>
/// <value>The record size in bytes.
/// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></value>
public int RecordSize => recordSize;
/// <summary>
/// Get the TAR Buffer's record size.
/// </summary>
/// <returns>The record size in bytes.
/// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></returns>
[Obsolete("Use RecordSize property instead")]
public int GetRecordSize()
{
return recordSize;
}
/// <summary>
/// Get the Blocking factor for the buffer
/// </summary>
/// <value>This is the number of blocks in each record.</value>
public int BlockFactor => blockFactor;
/// <summary>
/// Get the TAR Buffer's block factor
/// </summary>
/// <returns>The block factor; the number of blocks per record.</returns>
[Obsolete("Use BlockFactor property instead")]
public int GetBlockFactor()
{
return blockFactor;
}
/// <summary>
/// Construct a default TarBuffer
/// </summary>
protected TarBuffer()
{
}
/// <summary>
/// Create TarBuffer for reading with default BlockFactor
/// </summary>
/// <param name="inputStream">Stream to buffer</param>
/// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>
public static TarBuffer CreateInputTarBuffer(Stream inputStream)
{
if (inputStream == null) {
throw new ArgumentNullException(nameof(inputStream));
}
return CreateInputTarBuffer(inputStream, DefaultBlockFactor);
}
/// <summary>
/// Construct TarBuffer for reading inputStream setting BlockFactor
/// </summary>
/// <param name="inputStream">Stream to buffer</param>
/// <param name="blockFactor">Blocking factor to apply</param>
/// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>
public static TarBuffer CreateInputTarBuffer(Stream inputStream, int blockFactor)
{
if (inputStream == null) {
throw new ArgumentNullException(nameof(inputStream));
}
if (blockFactor <= 0) {
throw new ArgumentOutOfRangeException(nameof(blockFactor), "Factor cannot be negative");
}
var tarBuffer = new TarBuffer
{
inputStream = inputStream,
outputStream = null
};
tarBuffer.Initialize(blockFactor);
return tarBuffer;
}
/// <summary>
/// Construct TarBuffer for writing with default BlockFactor
/// </summary>
/// <param name="outputStream">output stream for buffer</param>
/// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>
public static TarBuffer CreateOutputTarBuffer(Stream outputStream)
{
if (outputStream == null) {
throw new ArgumentNullException(nameof(outputStream));
}
return CreateOutputTarBuffer(outputStream, DefaultBlockFactor);
}
/// <summary>
/// Construct TarBuffer for writing Tar output to streams.
/// </summary>
/// <param name="outputStream">Output stream to write to.</param>
/// <param name="blockFactor">Blocking factor to apply</param>
/// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>
public static TarBuffer CreateOutputTarBuffer(Stream outputStream, int blockFactor)
{
if (outputStream == null) {
throw new ArgumentNullException(nameof(outputStream));
}
if (blockFactor <= 0) {
throw new ArgumentOutOfRangeException(nameof(blockFactor), "Factor cannot be negative");
}
var tarBuffer = new TarBuffer();
tarBuffer.inputStream = null;
tarBuffer.outputStream = outputStream;
tarBuffer.Initialize(blockFactor);
return tarBuffer;
}
/// <summary>
/// Initialization common to all constructors.
/// </summary>
void Initialize(int archiveBlockFactor)
{
blockFactor = archiveBlockFactor;
recordSize = archiveBlockFactor * BlockSize;
recordBuffer = new byte[RecordSize];
if (inputStream != null) {
currentRecordIndex = -1;
currentBlockIndex = BlockFactor;
} else {
currentRecordIndex = 0;
currentBlockIndex = 0;
}
}
/// <summary>
/// Determine if an archive block indicates End of Archive. End of
/// archive is indicated by a block that consists entirely of null bytes.
/// All remaining blocks for the record should also be null's
/// However some older tars only do a couple of null blocks (Old GNU tar for one)
/// and also partial records
/// </summary>
/// <param name = "block">The data block to check.</param>
/// <returns>Returns true if the block is an EOF block; false otherwise.</returns>
[Obsolete("Use IsEndOfArchiveBlock instead")]
public bool IsEOFBlock(byte[] block)
{
if (block == null) {
throw new ArgumentNullException(nameof(block));
}
if (block.Length != BlockSize) {
throw new ArgumentException("block length is invalid");
}
for (int i = 0; i < BlockSize; ++i) {
if (block[i] != 0) {
return false;
}
}
return true;
}
/// <summary>
/// Determine if an archive block indicates the End of an Archive has been reached.
/// End of archive is indicated by a block that consists entirely of null bytes.
/// All remaining blocks for the record should also be null's
/// However some older tars only do a couple of null blocks (Old GNU tar for one)
/// and also partial records
/// </summary>
/// <param name = "block">The data block to check.</param>
/// <returns>Returns true if the block is an EOF block; false otherwise.</returns>
public static bool IsEndOfArchiveBlock(byte[] block)
{
if (block == null) {
throw new ArgumentNullException(nameof(block));
}
if (block.Length != BlockSize) {
throw new ArgumentException("block length is invalid");
}
for (int i = 0; i < BlockSize; ++i) {
if (block[i] != 0) {
return false;
}
}
return true;
}
/// <summary>
/// Skip over a block on the input stream.
/// </summary>
public void SkipBlock()
{
if (inputStream == null) {
throw new TarException("no input stream defined");
}
if (currentBlockIndex >= BlockFactor) {
if (!ReadRecord()) {
throw new TarException("Failed to read a record");
}
}
currentBlockIndex++;
}
/// <summary>
/// Read a block from the input stream.
/// </summary>
/// <returns>
/// The block of data read.
/// </returns>
public byte[] ReadBlock()
{
if (inputStream == null) {
throw new TarException("TarBuffer.ReadBlock - no input stream defined");
}
if (currentBlockIndex >= BlockFactor) {
if (!ReadRecord()) {
throw new TarException("Failed to read a record");
}
}
byte[] result = new byte[BlockSize];
Array.Copy(recordBuffer, (currentBlockIndex * BlockSize), result, 0, BlockSize);
currentBlockIndex++;
return result;
}
/// <summary>
/// Read a record from data stream.
/// </summary>
/// <returns>
/// false if End-Of-File, else true.
/// </returns>
bool ReadRecord()
{
if (inputStream == null) {
throw new TarException("no input stream stream defined");
}
currentBlockIndex = 0;
int offset = 0;
int bytesNeeded = RecordSize;
while (bytesNeeded > 0) {
long numBytes = inputStream.Read(recordBuffer, offset, bytesNeeded);
//
// NOTE
// We have found EOF, and the record is not full!
//
// This is a broken archive. It does not follow the standard
// blocking algorithm. However, because we are generous, and
// it requires little effort, we will simply ignore the error
// and continue as if the entire record were read. This does
// not appear to break anything upstream. We used to return
// false in this case.
//
// Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
//
if (numBytes <= 0) {
break;
}
offset += (int)numBytes;
bytesNeeded -= (int)numBytes;
}
currentRecordIndex++;
return true;
}
/// <summary>
/// Get the current block number, within the current record, zero based.
/// </summary>
/// <remarks>Block numbers are zero based values</remarks>
/// <seealso cref="RecordSize"/>
public int CurrentBlock => currentBlockIndex;
/// <summary>
/// Get/set flag indicating ownership of the underlying stream.
/// When the flag is true <see cref="Close"></see> will close the underlying stream also.
/// </summary>
public bool IsStreamOwner {
get => isStreamOwner_;
set => isStreamOwner_ = value;
}
/// <summary>
/// Get the current block number, within the current record, zero based.
/// </summary>
/// <returns>
/// The current zero based block number.
/// </returns>
/// <remarks>
/// The absolute block number = (<see cref="GetCurrentRecordNum">record number</see> * <see cref="BlockFactor">block factor</see>) + <see cref="GetCurrentBlockNum">block number</see>.
/// </remarks>
[Obsolete("Use CurrentBlock property instead")]
public int GetCurrentBlockNum()
{
return currentBlockIndex;
}
/// <summary>
/// Get the current record number.
/// </summary>
/// <returns>
/// The current zero based record number.
/// </returns>
public int CurrentRecord => currentRecordIndex;
/// <summary>
/// Get the current record number.
/// </summary>
/// <returns>
/// The current zero based record number.
/// </returns>
[Obsolete("Use CurrentRecord property instead")]
public int GetCurrentRecordNum()
{
return currentRecordIndex;
}
/// <summary>
/// Write a block of data to the archive.
/// </summary>
/// <param name="block">
/// The data to write to the archive.
/// </param>
public void WriteBlock(byte[] block)
{
if (block == null) {
throw new ArgumentNullException(nameof(block));
}
if (outputStream == null) {
throw new TarException("TarBuffer.WriteBlock - no output stream defined");
}
if (block.Length != BlockSize) {
string errorText = string.Format("TarBuffer.WriteBlock - block to write has length '{0}' which is not the block size of '{1}'",
block.Length, BlockSize);
throw new TarException(errorText);
}
if (currentBlockIndex >= BlockFactor) {
WriteRecord();
}
Array.Copy(block, 0, recordBuffer, (currentBlockIndex * BlockSize), BlockSize);
currentBlockIndex++;
}
/// <summary>
/// Write an archive record to the archive, where the record may be
/// inside of a larger array buffer. The buffer must be "offset plus
/// record size" long.
/// </summary>
/// <param name="buffer">
/// The buffer containing the record data to write.
/// </param>
/// <param name="offset">
/// The offset of the record data within buffer.
/// </param>
public void WriteBlock(byte[] buffer, int offset)
{
if (buffer == null) {
throw new ArgumentNullException(nameof(buffer));
}
if (outputStream == null) {
throw new TarException("TarBuffer.WriteBlock - no output stream stream defined");
}
if ((offset < 0) || (offset >= buffer.Length)) {
throw new ArgumentOutOfRangeException(nameof(offset));
}
if ((offset + BlockSize) > buffer.Length) {
string errorText = string.Format("TarBuffer.WriteBlock - record has length '{0}' with offset '{1}' which is less than the record size of '{2}'",
buffer.Length, offset, recordSize);
throw new TarException(errorText);
}
if (currentBlockIndex >= BlockFactor) {
WriteRecord();
}
Array.Copy(buffer, offset, recordBuffer, (currentBlockIndex * BlockSize), BlockSize);
currentBlockIndex++;
}
/// <summary>
/// Write a TarBuffer record to the archive.
/// </summary>
void WriteRecord()
{
if (outputStream == null) {
throw new TarException("TarBuffer.WriteRecord no output stream defined");
}
outputStream.Write(recordBuffer, 0, RecordSize);
outputStream.Flush();
currentBlockIndex = 0;
currentRecordIndex++;
}
/// <summary>
/// WriteFinalRecord writes the current record buffer to output any unwritten data is present.
/// </summary>
/// <remarks>Any trailing bytes are set to zero which is by definition correct behaviour
/// for the end of a tar stream.</remarks>
void WriteFinalRecord()
{
if (outputStream == null) {
throw new TarException("TarBuffer.WriteFinalRecord no output stream defined");
}
if (currentBlockIndex > 0) {
int dataBytes = currentBlockIndex * BlockSize;
Array.Clear(recordBuffer, dataBytes, RecordSize - dataBytes);
WriteRecord();
}
outputStream.Flush();
}
/// <summary>
/// Close the TarBuffer. If this is an output buffer, also flush the
/// current block before closing.
/// </summary>
public void Close()
{
if (outputStream != null) {
WriteFinalRecord();
if (isStreamOwner_) {
outputStream.Dispose();
}
outputStream = null;
} else if (inputStream != null) {
if (isStreamOwner_) {
inputStream.Dispose();
}
inputStream = null;
}
}
#region Instance Fields
Stream inputStream;
Stream outputStream;
byte[] recordBuffer;
int currentBlockIndex;
int currentRecordIndex;
int recordSize = DefaultRecordSize;
int blockFactor = DefaultBlockFactor;
bool isStreamOwner_ = true;
#endregion
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Common.Tar
@@ -15,49 +16,46 @@ namespace SharpCompress.Common.Tar
CompressionType = type;
}
internal TarHeader Header => filePart.Header;
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.ModTime;
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.TypeFlag == TarHeader.LF_DIR;
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)
{
using (var tarStream = new TarInputStream(stream))
foreach (TarHeader h in TarHeaderFactory.ReadHeader(mode, stream))
{
TarHeader header = null;
while ((header = tarStream.GetNextEntry()) != null)
if (h != null)
{
if (mode == StreamingMode.Seekable)
{
yield return new TarEntry(new TarFilePart(header, stream), compressionType);
yield return new TarEntry(new TarFilePart(h, stream), compressionType);
}
else
{
yield return new TarEntry(new TarFilePart(header, null), compressionType);
yield return new TarEntry(new TarFilePart(h, null), compressionType);
}
}
}

View File

@@ -1,19 +0,0 @@
using System;
namespace SharpCompress.Common.Tar
{
/// <summary>
/// TarException represents exceptions specific to Tar classes and code.
/// </summary>
public class TarException : ArchiveException
{
/// <summary>
/// Initialise a new instance of <see cref="TarException" /> with its message string.
/// </summary>
/// <param name="message">A <see cref="string"/> that describes the error.</param>
public TarException(string message)
: base(message)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.IO;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Common.Tar
@@ -15,7 +16,7 @@ namespace SharpCompress.Common.Tar
internal TarHeader Header { get; }
internal override string FilePartName => Header.Name;
internal override string FilePartName { get { return Header.Name; } }
internal override Stream GetCompressedStream()
{

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Common.Tar
{
internal static class TarHeaderFactory
{
internal static IEnumerable<TarHeader> ReadHeader(StreamingMode mode, Stream stream)
{
while (true)
{
TarHeader header = null;
try
{
BinaryReader reader = new BinaryReader(stream);
header = new TarHeader();
if (!header.Read(reader))
{
yield break;
}
switch (mode)
{
case StreamingMode.Seekable:
{
header.DataStartPosition = reader.BaseStream.Position;
//skip to nearest 512
reader.BaseStream.Position += PadTo512(header.Size);
}
break;
case StreamingMode.Streaming:
{
header.PackedStream = new TarReadOnlySubStream(stream, header.Size);
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
}
}
catch
{
header = null;
}
yield return header;
}
}
private static long PadTo512(long size)
{
int zeros = (int)(size % 512);
if (zeros == 0)
{
return size;
}
return 512 - zeros + size;
}
}
}

View File

@@ -1,547 +0,0 @@
using System;
using System.IO;
using System.Text;
namespace SharpCompress.Common.Tar
{
/// <summary>
/// The TarInputStream reads a UNIX tar archive as an InputStream.
/// methods are provided to position at each successive entry in
/// the archive, and the read each entry as a normal input stream
/// using read().
/// </summary>
public class TarInputStream : Stream
{
#region Constructors
/// <summary>
/// Construct a TarInputStream with default block factor
/// </summary>
/// <param name="inputStream">stream to source data from</param>
public TarInputStream(Stream inputStream)
: this(inputStream, TarBuffer.DefaultBlockFactor)
{
}
/// <summary>
/// Construct a TarInputStream with user specified block factor
/// </summary>
/// <param name="inputStream">stream to source data from</param>
/// <param name="blockFactor">block factor to apply to archive</param>
public TarInputStream(Stream inputStream, int blockFactor)
{
this.inputStream = inputStream;
tarBuffer = TarBuffer.CreateInputTarBuffer(inputStream, blockFactor);
}
#endregion
/// <summary>
/// Get/set flag indicating ownership of the underlying stream.
/// When the flag is true <see cref="Close"></see> will close the underlying stream also.
/// </summary>
public bool IsStreamOwner { get => tarBuffer.IsStreamOwner; set => tarBuffer.IsStreamOwner = value; }
#region Stream Overrides
/// <summary>
/// Gets a value indicating whether the current stream supports reading
/// </summary>
public override bool CanRead => inputStream.CanRead;
/// <summary>
/// Gets a value indicating whether the current stream supports seeking
/// This property always returns false.
/// </summary>
public override bool CanSeek => false;
/// <summary>
/// Gets a value indicating if the stream supports writing.
/// This property always returns false.
/// </summary>
public override bool CanWrite => false;
/// <summary>
/// The length in bytes of the stream
/// </summary>
public override long Length => inputStream.Length;
/// <summary>
/// Gets or sets the position within the stream.
/// Setting the Position is not supported and throws a NotSupportedExceptionNotSupportedException
/// </summary>
/// <exception cref="NotSupportedException">Any attempt to set position</exception>
public override long Position { get => inputStream.Position; set => throw new NotSupportedException("TarInputStream Seek not supported"); }
/// <summary>
/// Flushes the baseInputStream
/// </summary>
public override void Flush()
{
inputStream.Flush();
}
/// <summary>
/// Set the streams position. This operation is not supported and will throw a NotSupportedException
/// </summary>
/// <param name="offset">The offset relative to the origin to seek to.</param>
/// <param name="origin">The <see cref="SeekOrigin"/> to start seeking from.</param>
/// <returns>The new position in the stream.</returns>
/// <exception cref="NotSupportedException">Any access</exception>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("TarInputStream Seek not supported");
}
/// <summary>
/// Sets the length of the stream
/// This operation is not supported and will throw a NotSupportedException
/// </summary>
/// <param name="value">The new stream length.</param>
/// <exception cref="NotSupportedException">Any access</exception>
public override void SetLength(long value)
{
throw new NotSupportedException("TarInputStream SetLength not supported");
}
/// <summary>
/// Writes a block of bytes to this stream using data from a buffer.
/// This operation is not supported and will throw a NotSupportedException
/// </summary>
/// <param name="buffer">The buffer containing bytes to write.</param>
/// <param name="offset">The offset in the buffer of the frist byte to write.</param>
/// <param name="count">The number of bytes to write.</param>
/// <exception cref="NotSupportedException">Any access</exception>
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException("TarInputStream Write not supported");
}
/// <summary>
/// Writes a byte to the current position in the file stream.
/// This operation is not supported and will throw a NotSupportedException
/// </summary>
/// <param name="value">The byte value to write.</param>
/// <exception cref="NotSupportedException">Any access</exception>
public override void WriteByte(byte value)
{
throw new NotSupportedException("TarInputStream WriteByte not supported");
}
/// <summary>
/// Reads a byte from the current tar archive entry.
/// </summary>
/// <returns>A byte cast to an int; -1 if the at the end of the stream.</returns>
public override int ReadByte()
{
byte[] oneByteBuffer = new byte[1];
int num = Read(oneByteBuffer, 0, 1);
if (num <= 0)
{
// return -1 to indicate that no byte was read.
return -1;
}
return oneByteBuffer[0];
}
/// <summary>
/// Reads bytes from the current tar archive entry.
///
/// This method is aware of the boundaries of the current
/// entry in the archive and will deal with them appropriately
/// </summary>
/// <param name="buffer">
/// The buffer into which to place bytes read.
/// </param>
/// <param name="offset">
/// The offset at which to place bytes read.
/// </param>
/// <param name="count">
/// The number of bytes to read.
/// </param>
/// <returns>
/// The number of bytes read, or 0 at end of stream/EOF.
/// </returns>
public override int Read(byte[] buffer, int offset, int count)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
int totalRead = 0;
if (entryOffset >= entrySize)
{
return 0;
}
long numToRead = count;
if ((numToRead + entryOffset) > entrySize)
{
numToRead = entrySize - entryOffset;
}
if (readBuffer != null)
{
int sz = (numToRead > readBuffer.Length) ? readBuffer.Length : (int)numToRead;
Array.Copy(readBuffer, 0, buffer, offset, sz);
if (sz >= readBuffer.Length)
{
readBuffer = null;
}
else
{
int newLen = readBuffer.Length - sz;
byte[] newBuf = new byte[newLen];
Array.Copy(readBuffer, sz, newBuf, 0, newLen);
readBuffer = newBuf;
}
totalRead += sz;
numToRead -= sz;
offset += sz;
}
while (numToRead > 0)
{
byte[] rec = tarBuffer.ReadBlock();
if (rec == null)
{
// Unexpected EOF!
throw new TarException("unexpected EOF with " + numToRead + " bytes unread");
}
var sz = (int)numToRead;
int recLen = rec.Length;
if (recLen > sz)
{
Array.Copy(rec, 0, buffer, offset, sz);
readBuffer = new byte[recLen - sz];
Array.Copy(rec, sz, readBuffer, 0, recLen - sz);
}
else
{
sz = recLen;
Array.Copy(rec, 0, buffer, offset, recLen);
}
totalRead += sz;
numToRead -= sz;
offset += sz;
}
entryOffset += totalRead;
return totalRead;
}
/// <summary>
/// Closes this stream. Calls the TarBuffer's close() method.
/// The underlying stream is closed by the TarBuffer.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing)
{
tarBuffer.Close();
}
}
#endregion
/// <summary>
/// Get the record size being used by this stream's TarBuffer.
/// </summary>
public int RecordSize => tarBuffer.RecordSize;
/// <summary>
/// Get the record size being used by this stream's TarBuffer.
/// </summary>
/// <returns>
/// TarBuffer record size.
/// </returns>
[Obsolete("Use RecordSize property instead")]
public int GetRecordSize()
{
return tarBuffer.RecordSize;
}
/// <summary>
/// Get the available data that can be read from the current
/// entry in the archive. This does not indicate how much data
/// is left in the entire archive, only in the current entry.
/// This value is determined from the entry's size header field
/// and the amount of data already read from the current entry.
/// </summary>
/// <returns>
/// The number of available bytes for the current entry.
/// </returns>
public long Available => entrySize - entryOffset;
/// <summary>
/// Skip bytes in the input buffer. This skips bytes in the
/// current entry's data, not the entire archive, and will
/// stop at the end of the current entry's data if the number
/// to skip extends beyond that point.
/// </summary>
/// <param name="skipCount">
/// The number of bytes to skip.
/// </param>
public void Skip(long skipCount)
{
// TODO: REVIEW efficiency of TarInputStream.Skip
// This is horribly inefficient, but it ensures that we
// properly skip over bytes via the TarBuffer...
//
byte[] skipBuf = new byte[8 * 1024];
for (long num = skipCount; num > 0;)
{
int toRead = num > skipBuf.Length ? skipBuf.Length : (int)num;
int numRead = Read(skipBuf, 0, toRead);
if (numRead == -1)
{
break;
}
num -= numRead;
}
}
/// <summary>
/// Return a value of true if marking is supported; false otherwise.
/// </summary>
/// <remarks>Currently marking is not supported, the return value is always false.</remarks>
public bool IsMarkSupported => false;
/// <summary>
/// Since we do not support marking just yet, we do nothing.
/// </summary>
/// <param name ="markLimit">
/// The limit to mark.
/// </param>
public void Mark(int markLimit)
{
}
/// <summary>
/// Since we do not support marking just yet, we do nothing.
/// </summary>
public void Reset()
{
}
/// <summary>
/// Get the next entry in this tar archive. This will skip
/// over any remaining data in the current entry, if there
/// is one, and place the input stream at the header of the
/// next entry, and read the header and instantiate a new
/// TarEntry from the header bytes and return that entry.
/// If there are no more entries in the archive, null will
/// be returned to indicate that the end of the archive has
/// been reached.
/// </summary>
/// <returns>
/// The next TarEntry in the archive, or null.
/// </returns>
public TarHeader GetNextEntry()
{
if (hasHitEOF)
{
return null;
}
if (currentEntry != null)
{
SkipToNextEntry();
}
byte[] headerBuf = tarBuffer.ReadBlock();
if (headerBuf == null)
{
hasHitEOF = true;
}
else
hasHitEOF |= TarBuffer.IsEndOfArchiveBlock(headerBuf);
if (hasHitEOF)
{
currentEntry = null;
}
else
{
try
{
var header = new TarHeader();
header.ParseBuffer(headerBuf);
if (!header.IsChecksumValid)
{
throw new TarException("Header checksum is invalid");
}
this.entryOffset = 0;
this.entrySize = header.Size;
StringBuilder longName = null;
if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME)
{
byte[] nameBuffer = new byte[TarBuffer.BlockSize];
long numToRead = this.entrySize;
longName = new StringBuilder();
while (numToRead > 0)
{
int numRead = this.Read(nameBuffer, 0, (numToRead > nameBuffer.Length ? nameBuffer.Length : (int)numToRead));
if (numRead == -1)
{
throw new TarException("Failed to read long name entry");
}
longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString());
numToRead -= numRead;
}
SkipToNextEntry();
headerBuf = this.tarBuffer.ReadBlock();
}
else if (header.TypeFlag == TarHeader.LF_GHDR)
{
// POSIX global extended header
// Ignore things we dont understand completely for now
SkipToNextEntry();
headerBuf = this.tarBuffer.ReadBlock();
}
else if (header.TypeFlag == TarHeader.LF_XHDR)
{
// POSIX extended header
// Ignore things we dont understand completely for now
SkipToNextEntry();
headerBuf = this.tarBuffer.ReadBlock();
}
else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR)
{
// TODO: could show volume name when verbose
SkipToNextEntry();
headerBuf = this.tarBuffer.ReadBlock();
}
else if (header.TypeFlag != TarHeader.LF_NORMAL &&
header.TypeFlag != TarHeader.LF_OLDNORM &&
header.TypeFlag != TarHeader.LF_LINK &&
header.TypeFlag != TarHeader.LF_SYMLINK &&
header.TypeFlag != TarHeader.LF_DIR)
{
// Ignore things we dont understand completely for now
SkipToNextEntry();
headerBuf = tarBuffer.ReadBlock();
}
currentEntry = new TarHeader();
if (longName != null)
{
currentEntry.Name = longName.ToString();
}
// Magic was checked here for 'ustar' but there are multiple valid possibilities
// so this is not done anymore.
entryOffset = 0;
// TODO: Review How do we resolve this discrepancy?!
entrySize = this.currentEntry.Size;
}
catch (TarException ex)
{
entrySize = 0;
entryOffset = 0;
currentEntry = null;
string errorText = $"Bad header in record {tarBuffer.CurrentRecord} block {tarBuffer.CurrentBlock} {ex.Message}";
throw new TarException(errorText);
}
}
return currentEntry;
}
/// <summary>
/// Copies the contents of the current tar archive entry directly into
/// an output stream.
/// </summary>
/// <param name="outputStream">
/// The OutputStream into which to write the entry's data.
/// </param>
public void CopyEntryContents(Stream outputStream)
{
byte[] tempBuffer = new byte[32 * 1024];
while (true)
{
int numRead = Read(tempBuffer, 0, tempBuffer.Length);
if (numRead <= 0)
{
break;
}
outputStream.Write(tempBuffer, 0, numRead);
}
}
private void SkipToNextEntry()
{
long numToSkip = entrySize - entryOffset;
if (numToSkip > 0)
{
Skip(numToSkip);
}
readBuffer = null;
}
#region Instance Fields
/// <summary>
/// Flag set when last block has been read
/// </summary>
protected bool hasHitEOF;
/// <summary>
/// Size of this entry as recorded in header
/// </summary>
protected long entrySize;
/// <summary>
/// Number of bytes read for this entry so far
/// </summary>
protected long entryOffset;
/// <summary>
/// Buffer used with calls to <code>Read()</code>
/// </summary>
protected byte[] readBuffer;
/// <summary>
/// Working buffer
/// </summary>
protected TarBuffer tarBuffer;
/// <summary>
/// Current entry being read
/// </summary>
private TarHeader currentEntry;
/// <summary>
/// Stream used as the source of input data.
/// </summary>
private readonly Stream inputStream;
#endregion
}
}

View File

@@ -1,417 +0,0 @@
using System;
using System.IO;
namespace SharpCompress.Common.Tar
{
/// <summary>
/// The TarOutputStream writes a UNIX tar archive as an OutputStream.
/// Methods are provided to put entries, and then write their contents
/// by writing to this stream using write().
/// </summary>
/// public
public class TarOutputStream : Stream
{
#region Constructors
/// <summary>
/// Construct TarOutputStream using default block factor
/// </summary>
/// <param name="outputStream">stream to write to</param>
public TarOutputStream(Stream outputStream)
: this(outputStream, TarBuffer.DefaultBlockFactor)
{
}
/// <summary>
/// Construct TarOutputStream with user specified block factor
/// </summary>
/// <param name="outputStream">stream to write to</param>
/// <param name="blockFactor">blocking factor</param>
public TarOutputStream(Stream outputStream, int blockFactor)
{
if (outputStream == null) {
throw new ArgumentNullException(nameof(outputStream));
}
this.outputStream = outputStream;
buffer = TarBuffer.CreateOutputTarBuffer(outputStream, blockFactor);
assemblyBuffer = new byte[TarBuffer.BlockSize];
blockBuffer = new byte[TarBuffer.BlockSize];
}
#endregion
/// <summary>
/// Get/set flag indicating ownership of the underlying stream.
/// When the flag is true <see cref="Close"></see> will close the underlying stream also.
/// </summary>
public bool IsStreamOwner {
get => buffer.IsStreamOwner;
set => buffer.IsStreamOwner = value;
}
/// <summary>
/// true if the stream supports reading; otherwise, false.
/// </summary>
public override bool CanRead => outputStream.CanRead;
/// <summary>
/// true if the stream supports seeking; otherwise, false.
/// </summary>
public override bool CanSeek => outputStream.CanSeek;
/// <summary>
/// true if stream supports writing; otherwise, false.
/// </summary>
public override bool CanWrite => outputStream.CanWrite;
/// <summary>
/// length of stream in bytes
/// </summary>
public override long Length => outputStream.Length;
/// <summary>
/// gets or sets the position within the current stream.
/// </summary>
public override long Position {
get => outputStream.Position;
set => outputStream.Position = value;
}
/// <summary>
/// set the position within the current stream
/// </summary>
/// <param name="offset">The offset relative to the <paramref name="origin"/> to seek to</param>
/// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
/// <returns>The new position in the stream.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
return outputStream.Seek(offset, origin);
}
/// <summary>
/// Set the length of the current stream
/// </summary>
/// <param name="value">The new stream length.</param>
public override void SetLength(long value)
{
outputStream.SetLength(value);
}
/// <summary>
/// Read a byte from the stream and advance the position within the stream
/// by one byte or returns -1 if at the end of the stream.
/// </summary>
/// <returns>The byte value or -1 if at end of stream</returns>
public override int ReadByte()
{
return outputStream.ReadByte();
}
/// <summary>
/// read bytes from the current stream and advance the position within the
/// stream by the number of bytes read.
/// </summary>
/// <param name="buffer">The buffer to store read bytes in.</param>
/// <param name="offset">The index into the buffer to being storing bytes at.</param>
/// <param name="count">The desired number of bytes to read.</param>
/// <returns>The total number of bytes read, or zero if at the end of the stream.
/// The number of bytes may be less than the <paramref name="count">count</paramref>
/// requested if data is not avialable.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
return outputStream.Read(buffer, offset, count);
}
/// <summary>
/// All buffered data is written to destination
/// </summary>
public override void Flush()
{
outputStream.Flush();
}
/// <summary>
/// Ends the TAR archive without closing the underlying OutputStream.
/// The result is that the EOF block of nulls is written.
/// </summary>
public void Finish()
{
if (IsEntryOpen) {
CloseEntry();
}
WriteEofBlock();
}
/// <summary>
/// Ends the TAR archive and closes the underlying OutputStream.
/// </summary>
/// <remarks>This means that Finish() is called followed by calling the
/// TarBuffer's Close().</remarks>
protected override void Dispose(bool disposing)
{
if (!isClosed) {
isClosed = true;
Finish();
buffer.Close();
}
}
/// <summary>
/// Get the record size being used by this stream's TarBuffer.
/// </summary>
public int RecordSize => buffer.RecordSize;
/// <summary>
/// Get the record size being used by this stream's TarBuffer.
/// </summary>
/// <returns>
/// The TarBuffer record size.
/// </returns>
[Obsolete("Use RecordSize property instead")]
public int GetRecordSize()
{
return buffer.RecordSize;
}
/// <summary>
/// Get a value indicating wether an entry is open, requiring more data to be written.
/// </summary>
bool IsEntryOpen => (currBytes < currSize);
/// <summary>
/// Put an entry on the output stream. This writes the entry's
/// header and positions the output stream for writing
/// the contents of the entry. Once this method is called, the
/// stream is ready for calls to write() to write the entry's
/// contents. Once the contents are written, closeEntry()
/// <B>MUST</B> be called to ensure that all buffered data
/// is completely written to the output stream.
/// </summary>
/// <param name="entry">
/// The TarEntry to be written to the archive.
/// </param>
public void PutNextEntry(TarEntry entry)
{
if (entry == null) {
throw new ArgumentNullException(nameof(entry));
}
if (entry.TarHeader.Name.Length > TarHeader.NAMELEN) {
var longHeader = new TarHeader();
longHeader.TypeFlag = TarHeader.LF_GNU_LONGNAME;
longHeader.Name = longHeader.Name + "././@LongLink";
longHeader.Mode = 420;//644 by default
longHeader.UserId = entry.UserId;
longHeader.GroupId = entry.GroupId;
longHeader.GroupName = entry.GroupName;
longHeader.UserName = entry.UserName;
longHeader.LinkName = "";
longHeader.Size = entry.TarHeader.Name.Length + 1; // Plus one to avoid dropping last char
longHeader.WriteHeader(blockBuffer);
buffer.WriteBlock(blockBuffer); // Add special long filename header block
int nameCharIndex = 0;
while (nameCharIndex < entry.TarHeader.Name.Length + 1 /* we've allocated one for the null char, now we must make sure it gets written out */) {
Array.Clear(blockBuffer, 0, blockBuffer.Length);
TarHeader.GetAsciiBytes(entry.TarHeader.Name, nameCharIndex, this.blockBuffer, 0, TarBuffer.BlockSize); // This func handles OK the extra char out of string length
nameCharIndex += TarBuffer.BlockSize;
buffer.WriteBlock(blockBuffer);
}
}
entry.WriteEntryHeader(blockBuffer);
buffer.WriteBlock(blockBuffer);
currBytes = 0;
currSize = entry.IsDirectory ? 0 : entry.Size;
}
/// <summary>
/// Close an entry. This method MUST be called for all file
/// entries that contain data. The reason is that we must
/// buffer data written to the stream in order to satisfy
/// the buffer's block based writes. Thus, there may be
/// data fragments still being assembled that must be written
/// to the output stream before this entry is closed and the
/// next entry written.
/// </summary>
public void CloseEntry()
{
if (assemblyBufferLength > 0) {
Array.Clear(assemblyBuffer, assemblyBufferLength, assemblyBuffer.Length - assemblyBufferLength);
buffer.WriteBlock(assemblyBuffer);
currBytes += assemblyBufferLength;
assemblyBufferLength = 0;
}
if (currBytes < currSize) {
string errorText = string.Format(
"Entry closed at '{0}' before the '{1}' bytes specified in the header were written",
currBytes, currSize);
throw new TarException(errorText);
}
}
/// <summary>
/// Writes a byte to the current tar archive entry.
/// This method simply calls Write(byte[], int, int).
/// </summary>
/// <param name="value">
/// The byte to be written.
/// </param>
public override void WriteByte(byte value)
{
Write(new byte[] { value }, 0, 1);
}
/// <summary>
/// Writes bytes to the current tar archive entry. This method
/// is aware of the current entry and will throw an exception if
/// you attempt to write bytes past the length specified for the
/// current entry. The method is also (painfully) aware of the
/// record buffering required by TarBuffer, and manages buffers
/// that are not a multiple of recordsize in length, including
/// assembling records from small buffers.
/// </summary>
/// <param name = "buffer">
/// The buffer to write to the archive.
/// </param>
/// <param name = "offset">
/// The offset in the buffer from which to get bytes.
/// </param>
/// <param name = "count">
/// The number of bytes to write.
/// </param>
public override void Write(byte[] buffer, int offset, int count)
{
if (buffer == null) {
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0) {
throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");
}
if (buffer.Length - offset < count) {
throw new ArgumentException("offset and count combination is invalid");
}
if (count < 0) {
throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");
}
if ((currBytes + count) > currSize) {
string errorText = string.Format("request to write '{0}' bytes exceeds size in header of '{1}' bytes",
count, this.currSize);
throw new ArgumentOutOfRangeException(nameof(count), errorText);
}
//
// We have to deal with assembly!!!
// The programmer can be writing little 32 byte chunks for all
// we know, and we must assemble complete blocks for writing.
// TODO REVIEW Maybe this should be in TarBuffer? Could that help to
// eliminate some of the buffer copying.
//
if (assemblyBufferLength > 0) {
if ((assemblyBufferLength + count) >= blockBuffer.Length) {
int aLen = blockBuffer.Length - assemblyBufferLength;
Array.Copy(assemblyBuffer, 0, blockBuffer, 0, assemblyBufferLength);
Array.Copy(buffer, offset, blockBuffer, assemblyBufferLength, aLen);
this.buffer.WriteBlock(blockBuffer);
currBytes += blockBuffer.Length;
offset += aLen;
count -= aLen;
assemblyBufferLength = 0;
} else {
Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count);
offset += count;
assemblyBufferLength += count;
count -= count;
}
}
//
// When we get here we have EITHER:
// o An empty "assembly" buffer.
// o No bytes to write (count == 0)
//
while (count > 0) {
if (count < blockBuffer.Length) {
Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count);
assemblyBufferLength += count;
break;
}
this.buffer.WriteBlock(buffer, offset);
int bufferLength = blockBuffer.Length;
currBytes += bufferLength;
count -= bufferLength;
offset += bufferLength;
}
}
/// <summary>
/// Write an EOF (end of archive) block to the tar archive.
/// An EOF block consists of all zeros.
/// </summary>
void WriteEofBlock()
{
Array.Clear(blockBuffer, 0, blockBuffer.Length);
buffer.WriteBlock(blockBuffer);
}
#region Instance Fields
/// <summary>
/// bytes written for this entry so far
/// </summary>
long currBytes;
/// <summary>
/// current 'Assembly' buffer length
/// </summary>
int assemblyBufferLength;
/// <summary>
/// Flag indicating wether this instance has been closed or not.
/// </summary>
bool isClosed;
/// <summary>
/// Size for the current entry
/// </summary>
protected long currSize;
/// <summary>
/// single block working buffer
/// </summary>
protected byte[] blockBuffer;
/// <summary>
/// 'Assembly' buffer used to assemble data before writing
/// </summary>
protected byte[] assemblyBuffer;
/// <summary>
/// TarBuffer used to provide correct blocking factor
/// </summary>
protected TarBuffer buffer;
/// <summary>
/// the destination stream for the archive contents
/// </summary>
protected Stream outputStream;
#endregion
}
}

View File

@@ -0,0 +1,90 @@
using System;
using System.IO;
namespace SharpCompress.Common.Tar
{
internal class TarReadOnlySubStream : Stream
{
private bool isDisposed;
private long amountRead;
public TarReadOnlySubStream(Stream stream, long bytesToRead)
{
Stream = stream;
BytesLeftToRead = bytesToRead;
}
protected override void Dispose(bool disposing)
{
if (isDisposed)
{
return;
}
isDisposed = true;
if (disposing)
{
long skipBytes = amountRead % 512;
if (skipBytes == 0)
{
return;
}
skipBytes = 512 - skipBytes;
if (skipBytes == 0)
{
return;
}
var buffer = new byte[skipBytes];
Stream.ReadFully(buffer);
}
}
private long BytesLeftToRead { get; set; }
public Stream Stream { get; }
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return false; } }
public override void Flush()
{
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 int Read(byte[] buffer, int offset, int count)
{
if (BytesLeftToRead < count)
{
count = (int)BytesLeftToRead;
}
int read = Stream.Read(buffer, offset, count);
if (read > 0)
{
BytesLeftToRead -= read;
amountRead += read;
}
return read;
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
}

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,5 +1,4 @@
using System;
using System.IO;
using System.IO;
using System.Linq;
namespace SharpCompress.Common.Zip.Headers
@@ -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

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

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

@@ -57,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.Read(buffer, 0, 12);
PkwareTraditionalEncryptionData encryptionData = PkwareTraditionalEncryptionData.ForRead(Password, this, buffer);
return encryptionData;
}
internal PkwareTraditionalEncryptionData PkwareTraditionalEncryptionData { get; set; }
#if !NO_CRYPTO
internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; }
#endif
@@ -112,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)
{

View File

@@ -9,10 +9,11 @@ namespace SharpCompress.Common.Zip
{
private static readonly CRC32 crc32 = new CRC32();
private readonly UInt32[] _Keys = {0x12345678, 0x23456789, 0x34567890};
private readonly string password;
private PkwareTraditionalEncryptionData(string password)
{
Initialize(password);
this.password = password;
}
private byte MagicByte
@@ -28,6 +29,7 @@ namespace SharpCompress.Common.Zip
byte[] encryptionHeader)
{
var encryptor = new PkwareTraditionalEncryptionData(password);
encryptor.InitializeKeys();
byte[] plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length);
if (plainTextHeader[11] != (byte)((header.Crc >> 24) & 0xff))
{
@@ -84,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++)

View File

@@ -24,7 +24,7 @@ namespace SharpCompress.Common.Zip
return base.GetCompressedStream();
}
internal string Comment => (Header as DirectoryEntryHeader).Comment;
internal string Comment { get { return (Header as DirectoryEntryHeader).Comment; } }
private void LoadLocalHeader()
{

View File

@@ -9,7 +9,6 @@ namespace SharpCompress.Common.Zip
internal class SeekableZipHeaderFactory : ZipHeaderFactory
{
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096;
private bool zip64;
internal SeekableZipHeaderFactory(string password)
: base(StreamingMode.Seekable, password)
@@ -17,56 +16,11 @@ namespace SharpCompress.Common.Zip
}
internal IEnumerable<DirectoryEntryHeader> ReadSeekableHeader(Stream stream)
{
var reader = new BinaryReader(stream);
SeekBackToHeader(stream, reader, DIRECTORY_END_HEADER_BYTES);
var entry = new DirectoryEndHeader();
entry.Read(reader);
if (entry.IsZip64)
{
zip64 = true;
SeekBackToHeader(stream, reader, ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR);
var zip64Locator = new Zip64DirectoryEndLocatorHeader();
zip64Locator.Read(reader);
stream.Seek(zip64Locator.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin);
uint zip64Signature = reader.ReadUInt32();
if(zip64Signature != ZIP64_END_OF_CENTRAL_DIRECTORY)
throw new ArchiveException("Failed to locate the Zip64 Header");
var zip64Entry = new Zip64DirectoryEndHeader();
zip64Entry.Read(reader);
stream.Seek(zip64Entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
}
else
{
stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
}
long position = stream.Position;
while (true)
{
stream.Position = position;
uint signature = reader.ReadUInt32();
var directoryEntryHeader = ReadHeader(signature, reader, zip64) as DirectoryEntryHeader;
position = stream.Position;
if (directoryEntryHeader == null)
{
yield break;
}
//entry could be zero bytes so we need to know that.
directoryEntryHeader.HasData = directoryEntryHeader.CompressedSize != 0;
yield return directoryEntryHeader;
}
}
private static void SeekBackToHeader(Stream stream, BinaryReader reader, uint headerSignature)
{
long offset = 0;
uint signature;
BinaryReader reader = new BinaryReader(stream);
int iterationCount = 0;
do
{
@@ -80,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)
@@ -91,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);

View File

@@ -28,7 +28,7 @@ namespace SharpCompress.Common.Zip
ZipHeader header = null;
BinaryReader reader = new BinaryReader(rewindableStream);
if (lastEntryHeader != null &&
(FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) || 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

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

@@ -21,10 +21,10 @@ namespace SharpCompress.Common.Zip
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()
{
@@ -32,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);
@@ -51,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:
{
@@ -102,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");
}
@@ -114,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:
{
@@ -125,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
}
@@ -142,40 +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

@@ -17,8 +17,8 @@ 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;
@@ -30,7 +30,7 @@ namespace SharpCompress.Common.Zip
this.password = password;
}
protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader, bool zip64 = false)
protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader)
{
switch (headerBytes)
{
@@ -54,12 +54,14 @@ namespace SharpCompress.Common.Zip
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();
lastEntryHeader.CompressedSize = reader.ReadUInt32();
lastEntryHeader.UncompressedSize = reader.ReadUInt32();
}
else
{
reader.ReadBytes(zip64 ? 20 : 12);
reader.ReadUInt32();
reader.ReadUInt32();
reader.ReadUInt32();
}
return null;
}
@@ -76,14 +78,9 @@ namespace SharpCompress.Common.Zip
return new SplitHeader();
}
case ZIP64_END_OF_CENTRAL_DIRECTORY:
{
var entry = new Zip64DirectoryEndHeader();
entry.Read(reader);
return entry;
}
case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR:
{
var entry = new Zip64DirectoryEndLocatorHeader();
var entry = new IgnoreHeader(ZipHeaderType.Ignore);
entry.Read(reader);
return entry;
}
@@ -114,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,15 +168,13 @@ namespace SharpCompress.Common.Zip
{
entryHeader.DataStartPosition = stream.Position;
stream.Position += entryHeader.CompressedSize;
break;
}
break;
case StreamingMode.Streaming:
{
entryHeader.PackedStream = stream;
break;
}
break;
default:
{
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()
{

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,7 +92,14 @@ 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.

View File

@@ -50,7 +50,7 @@ namespace SharpCompress.Compressors.Deflate
/// </remarks>
public virtual FlushType FlushMode
{
get => (_baseStream._flushMode);
get { return (_baseStream._flushMode); }
set
{
if (_disposed)
@@ -80,7 +80,7 @@ namespace SharpCompress.Compressors.Deflate
/// </remarks>
public int BufferSize
{
get => _baseStream._bufferSize;
get { return _baseStream._bufferSize; }
set
{
if (_disposed)
@@ -111,7 +111,7 @@ namespace SharpCompress.Compressors.Deflate
/// </remarks>
public CompressionStrategy Strategy
{
get => _baseStream.Strategy;
get { return _baseStream.Strategy; }
set
{
if (_disposed)
@@ -123,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
@@ -156,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.
@@ -179,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.
@@ -206,7 +206,7 @@ namespace SharpCompress.Compressors.Deflate
}
return 0;
}
set => throw new NotSupportedException();
set { throw new NotSupportedException(); }
}
/// <summary>
@@ -342,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

@@ -71,7 +71,7 @@ namespace SharpCompress.Compressors.Deflate
public virtual FlushType FlushMode
{
get => (BaseStream._flushMode);
get { return (BaseStream._flushMode); }
set
{
if (disposed)
@@ -84,7 +84,7 @@ namespace SharpCompress.Compressors.Deflate
public int BufferSize
{
get => BaseStream._bufferSize;
get { return BaseStream._bufferSize; }
set
{
if (disposed)
@@ -105,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
@@ -137,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.
@@ -160,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.
@@ -188,7 +188,7 @@ namespace SharpCompress.Compressors.Deflate
return 0;
}
set => throw new NotSupportedException();
set { throw new NotSupportedException(); }
}
/// <summary>
@@ -350,7 +350,7 @@ namespace SharpCompress.Compressors.Deflate
public String Comment
{
get => comment;
get { return comment; }
set
{
if (disposed)
@@ -363,7 +363,7 @@ namespace SharpCompress.Compressors.Deflate
public string FileName
{
get => fileName;
get { return fileName; }
set
{
if (disposed)

View File

@@ -28,6 +28,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.Converters;
namespace SharpCompress.Compressors.Deflate
@@ -97,7 +98,7 @@ namespace SharpCompress.Compressors.Deflate
}
}
protected internal bool _wantCompress => (_compressionMode == CompressionMode.Compress);
protected internal bool _wantCompress { get { return (_compressionMode == CompressionMode.Compress); } }
private ZlibCodec z
{
@@ -629,15 +630,15 @@ namespace SharpCompress.Compressors.Deflate
return rc;
}
public override Boolean CanRead => _stream.CanRead;
public override Boolean CanRead { get { return _stream.CanRead; } }
public override Boolean CanSeek => _stream.CanSeek;
public override Boolean CanSeek { get { return _stream.CanSeek; } }
public override Boolean CanWrite => _stream.CanWrite;
public override Boolean CanWrite { get { return _stream.CanWrite; } }
public override Int64 Length => _stream.Length;
public override Int64 Length { get { return _stream.Length; } }
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } }
internal enum StreamMode
{

View File

@@ -171,7 +171,7 @@ namespace SharpCompress.Compressors.Deflate
/// <summary>
/// The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this.
/// </summary>
public int Adler32 => (int)_Adler32;
public int Adler32 { get { return (int)_Adler32; } }
/// <summary>
/// Create a ZlibCodec.

View File

@@ -63,7 +63,7 @@ namespace SharpCompress.Compressors.Deflate
/// </summary>
public virtual FlushType FlushMode
{
get => (_baseStream._flushMode);
get { return (_baseStream._flushMode); }
set
{
if (_disposed)
@@ -93,7 +93,7 @@ namespace SharpCompress.Compressors.Deflate
/// </remarks>
public int BufferSize
{
get => _baseStream._bufferSize;
get { return _baseStream._bufferSize; }
set
{
if (_disposed)
@@ -115,10 +115,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
@@ -148,7 +148,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.
@@ -171,7 +171,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.
@@ -199,7 +199,7 @@ namespace SharpCompress.Compressors.Deflate
return 0;
}
set => throw new NotSupportedException();
set { throw new NotSupportedException(); }
}
/// <summary>

View File

@@ -78,20 +78,20 @@ namespace SharpCompress.Compressors.Filters
baseStream.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 => baseStream.Length + data1.Length + data2.Length;
public override long Length { get { return baseStream.Length + data1.Length + data2.Length; } }
public override long Position { get => position; set => throw new NotSupportedException(); }
public override long Position { get { return position; } set { throw new NotSupportedException(); } }
public override int Read(byte[] buffer, int offset, int count)
{

View File

@@ -34,20 +34,20 @@ namespace SharpCompress.Compressors.Filters
baseStream.Dispose();
}
public override bool CanRead => !isEncoder;
public override bool CanRead { get { return !isEncoder; } }
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
public override bool CanWrite => isEncoder;
public override bool CanWrite { get { return isEncoder; } }
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length => baseStream.Length;
public override long Length { get { return baseStream.Length; } }
public override long Position { get => baseStream.Position; set => throw new NotSupportedException(); }
public override long Position { get { return baseStream.Position; } set { throw new NotSupportedException(); } }
public override int Read(byte[] buffer, int offset, int count)
{

View File

@@ -8,20 +8,20 @@ namespace SharpCompress.Compressors.LZMA
{
internal abstract class DecoderStream2 : 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 long Seek(long offset, SeekOrigin origin)
{

View File

@@ -178,6 +178,6 @@ namespace SharpCompress.Compressors.LZMA.LZ
_streamPos -= (UInt32)subValue;
}
public bool IsDataStarved => _streamPos - _pos < _keepSizeAfter;
public bool IsDataStarved { get { return _streamPos - _pos < _keepSizeAfter; } }
}
}

View File

@@ -166,9 +166,9 @@ namespace SharpCompress.Compressors.LZMA.LZ
Limit = Total + size;
}
public bool HasSpace => _pos < _windowSize && Total < Limit;
public bool HasSpace { get { return _pos < _windowSize && Total < Limit; } }
public bool HasPending => _pendingLen > 0;
public bool HasPending { get { return _pendingLen > 0; } }
public int Read(byte[] buffer, int offset, int count)
{
@@ -200,6 +200,6 @@ namespace SharpCompress.Compressors.LZMA.LZ
}
}
public int AvailableBytes => _pos - _streamPos;
public int AvailableBytes { get { return _pos - _streamPos; } }
}
}

View File

@@ -69,9 +69,9 @@ namespace SharpCompress.Compressors.LZMA
// TODO: Both Length and Position are sometimes feasible, but would require
// reading the output length when we initialize.
public override long Length => throw new NotImplementedException();
public override long Length { get { throw new NotImplementedException(); } }
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
public override int Read(byte[] buffer, int offset, int count) => stream.Read(buffer, offset, count);

View File

@@ -118,11 +118,11 @@ namespace SharpCompress.Compressors.LZMA
}
}
public override bool CanRead => encoder == null;
public override bool CanRead { get { return encoder == null; } }
public override bool CanSeek => false;
public override bool CanSeek { get { return false; } }
public override bool CanWrite => encoder != null;
public override bool CanWrite { get { return encoder != null; } }
public override void Flush()
{
@@ -149,9 +149,9 @@ namespace SharpCompress.Compressors.LZMA
base.Dispose(disposing);
}
public override long Length => position + availableBytes;
public override long Length { get { return position + availableBytes; } }
public override long Position { get => position; set => throw new NotSupportedException(); }
public override long Position { get { return position; } set { throw new NotSupportedException(); } }
public override int Read(byte[] buffer, int offset, int count)
{

View File

@@ -245,7 +245,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder
return symbol;
}
public bool IsFinished => Code == 0;
public bool IsFinished { get { return Code == 0; } }
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
}

View File

@@ -40,19 +40,19 @@ namespace SharpCompress.Compressors.LZMA.Utilites
return mCRC;
}
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 void Flush()
{
}
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)
{
@@ -122,20 +122,20 @@ namespace SharpCompress.Compressors.LZMA.Utilites
return mCRC;
}
public override bool CanRead => mSource.CanRead;
public override bool CanRead { get { return mSource.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 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

@@ -62,19 +62,19 @@ namespace SharpCompress.Compressors.LZMA.Utilites
}
}
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 void Flush()
{
}
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)
{

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