diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..92cbdb1d6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,35 @@ +# editorconfig.org + +# top-most EditorConfig file +root = true + +# Default settings: +# A newline ending every file +# Use 4 spaces as indentation +[*] +insert_final_newline = true +indent_style = tab +indent_size = 4 + +# C++ Files +[*.{cpp,h,in}] +curly_bracket_next_line = true +indent_brace_style = Allman + +# Xml project files +[*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}] +indent_size = 2 + +# Xml files +[*.{xml,stylecop,resx,ruleset}] +indent_size = 2 + +# Xml config files +[*.{props,targets,config,nuspec}] +indent_size = 2 + +# Shell scripts +[*.sh] +end_of_line = lf +[*.{cmd, bat}] +end_of_line = crlf diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..87a3690c0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,67 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain + +# Force bash scripts to always use lf line endings so that if a repo is accessed +# in Unix via a file share from Windows, the scripts will work. +*.sh text eol=lf diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000..f54527ec0 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,11 @@ +# Contributing to SharpZipLib + +Thanks for helping to improve SharpZipLib. + +In order for your changes to be accepted you can either sign the [Joint Copyright Assignment](http://www.icsharpcode.net/TechNotes/JointCopyrightAssignment.pdf) or add the following statement to your pull request: + +_I certify that I own, and have sufficient rights to contribute, all source code and related material intended to be compiled or integrated with the source code for the SharpZipLib open source product (the "Contribution"). My Contribution is licensed under the MIT License._ + +Unless we have a Joint Copyright Agreement on file or this statement is in your pull request, we cannot accept it. + +More information is available on [joining the team](https://github.com/icsharpcode/SharpDevelop/wiki/Joining-the-Team). diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..5a6112fdf --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,25 @@ +### Steps to reproduce +1. +2. +3. + +### Expected behavior +Tell us what should happen + +### Actual behavior +Tell us what happens instead + +### Version of SharpZipLib + +### Obtained from (place an x between the brackets for all that apply) +- [ ] Compiled from source + - branch: _______ + - commit: _______ +- [ ] Downloaded DLL from GitHub +- [ ] Downloaded DLL from SourceForge +- [ ] Downloaded DLL from _______ +- [ ] DLL included as part of +- Package installed using: + - [ ] NuGet + - [ ] MyGet + - [ ] Chocolatey diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..d97ce8065 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,4 @@ + +_I certify that I own, and have sufficient rights to contribute, all source code and related material intended to be compiled or integrated with the source code for the SharpZipLib open source product (the "Contribution"). My Contribution is licensed under the MIT License._ diff --git a/.gitignore b/.gitignore index a68645448..f1e3d20e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,252 @@ -/tests -/bin -/src/obj +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..6d42096ec --- /dev/null +++ b/.travis.yml @@ -0,0 +1,28 @@ +language: csharp +mono: + - latest +os: + - linux + - osx +solution: ICSharpCode.SharpZipLib.sln +install: + - nuget restore ICSharpCode.SharpZipLib.sln +script: + - xbuild /p:Configuration=Debug ICSharpCode.SharpZipLib.sln + - xbuild /p:Configuration=Release ICSharpCode.SharpZipLib.sln + - mono ./packages/NUnit.ConsoleRunner.3.2.1/tools/nunit3-console.exe --framework=mono-4.0 --labels=All --result=./Documentation/nunit3-test-results-travis.xml ./bin/Release/ICSharpCode.SharpZipLib.Tests.dll +after_script: + - nuget pack Build/ICSharpCode.SharpZipLib.nuspec -BasePath Build -OutputDirectory bin/Release +cache: + directories: + - bin + - Documentation +#deploy: +# provider: releases +# api_key: "GITHUB OAUTH TOKEN" +# file: +# - "bin/Release/ICSharpCode.SharpZipLib.nupkg" +# - "Documentation/nunit3-test-results-travis.xml" +# skip_cleanup: true +# on: +# tags: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..f54527ec0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,11 @@ +# Contributing to SharpZipLib + +Thanks for helping to improve SharpZipLib. + +In order for your changes to be accepted you can either sign the [Joint Copyright Assignment](http://www.icsharpcode.net/TechNotes/JointCopyrightAssignment.pdf) or add the following statement to your pull request: + +_I certify that I own, and have sufficient rights to contribute, all source code and related material intended to be compiled or integrated with the source code for the SharpZipLib open source product (the "Contribution"). My Contribution is licensed under the MIT License._ + +Unless we have a Joint Copyright Agreement on file or this statement is in your pull request, we cannot accept it. + +More information is available on [joining the team](https://github.com/icsharpcode/SharpDevelop/wiki/Joining-the-Team). diff --git a/ICSharpCode.SharpZLib.cmbx b/ICSharpCode.SharpZLib.cmbx deleted file mode 100644 index 9bd6adfaa..000000000 --- a/ICSharpCode.SharpZLib.cmbx +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/ICSharpCode.SharpZLib.sln b/ICSharpCode.SharpZLib.sln deleted file mode 100644 index 079435eff..000000000 --- a/ICSharpCode.SharpZLib.sln +++ /dev/null @@ -1,27 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -# SharpDevelop 2.2.1.2660 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpZipLibTests", "tests\SharpZipLibTests.csproj", "{4F9BF21E-A7FC-4005-A1C7-A17108F7010D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZLib", "src\ICSharpCode.SharpZLib.csproj", "{0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.Build.0 = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/ICSharpCode.SharpZLib2005.sln b/ICSharpCode.SharpZLib2005.sln deleted file mode 100644 index 079435eff..000000000 --- a/ICSharpCode.SharpZLib2005.sln +++ /dev/null @@ -1,27 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -# SharpDevelop 2.2.1.2660 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpZipLibTests", "tests\SharpZipLibTests.csproj", "{4F9BF21E-A7FC-4005-A1C7-A17108F7010D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZLib", "src\ICSharpCode.SharpZLib.csproj", "{0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.Build.0 = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/ICSharpCode.SharpZLib2008.sln b/ICSharpCode.SharpZLib2008.sln deleted file mode 100644 index 98c94ab78..000000000 --- a/ICSharpCode.SharpZLib2008.sln +++ /dev/null @@ -1,26 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpZipLibTests", "tests\SharpZipLibTests.csproj", "{4F9BF21E-A7FC-4005-A1C7-A17108F7010D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZLib", "src\ICSharpCode.SharpZLib.csproj", "{0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.Build.0 = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/ICSharpCode.SharpZipLib.sln b/ICSharpCode.SharpZipLib.sln new file mode 100644 index 000000000..8d183664a --- /dev/null +++ b/ICSharpCode.SharpZipLib.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.9 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Configuration", "Solution Configuration", "{F1097E98-4DEB-4A0A-81EE-5CEC667EBDF0}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + Rebracer.xml = Rebracer.xml + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.SharpZipLib", "src\ICSharpCode.SharpZipLib\ICSharpCode.SharpZipLib.csproj", "{C53BEB8A-0989-43A7-B3EC-F7028749FA71}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.SharpZipLib.Tests", "test\ICSharpCode.SharpZipLib.Tests\ICSharpCode.SharpZipLib.Tests.csproj", "{82211166-9C45-4603-8E3A-2CA2EFFCBC26}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZipLib.TestBootstrapper", "test\ICSharpCode.SharpZipLib.TestBootstrapper\ICSharpCode.SharpZipLib.TestBootstrapper.csproj", "{535D7365-C5B1-4253-9233-D72D972CA851}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C53BEB8A-0989-43A7-B3EC-F7028749FA71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C53BEB8A-0989-43A7-B3EC-F7028749FA71}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C53BEB8A-0989-43A7-B3EC-F7028749FA71}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C53BEB8A-0989-43A7-B3EC-F7028749FA71}.Release|Any CPU.Build.0 = Release|Any CPU + {82211166-9C45-4603-8E3A-2CA2EFFCBC26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {82211166-9C45-4603-8E3A-2CA2EFFCBC26}.Debug|Any CPU.Build.0 = Debug|Any CPU + {82211166-9C45-4603-8E3A-2CA2EFFCBC26}.Release|Any CPU.ActiveCfg = Release|Any CPU + {82211166-9C45-4603-8E3A-2CA2EFFCBC26}.Release|Any CPU.Build.0 = Release|Any CPU + {535D7365-C5B1-4253-9233-D72D972CA851}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {535D7365-C5B1-4253-9233-D72D972CA851}.Debug|Any CPU.Build.0 = Debug|Any CPU + {535D7365-C5B1-4253-9233-D72D972CA851}.Release|Any CPU.ActiveCfg = Release|Any CPU + {535D7365-C5B1-4253-9233-D72D972CA851}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..396840e00 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,17 @@ +Copyright © 2000-2016 SharpZipLib Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 38e7d399a..cfc5b9118 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,47 @@ -SharpZipLib -=========== +# SharpZipLib [![Build status](https://ci.appveyor.com/api/projects/status/wuf8l79mypqsbor3/branch/master?svg=true)](https://ci.appveyor.com/project/icsharpcode/sharpziplib/branch/master) [![Join the chat at https://gitter.im/icsharpcode/SharpZipLib](https://badges.gitter.im/icsharpcode/SharpZipLib.svg)](https://gitter.im/icsharpcode/SharpZipLib?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +The SharpZipLib project is looking for a new maintainer - please read [State of the Union August 2017](https://github.com/icsharpcode/SharpZipLib/issues/187) + +Introduction +------------ + +SharpZipLib (\#ziplib, formerly NZipLib) is a compression library that supports Zip files using both stored and deflate compression methods, PKZIP 2.0 style and AES encryption, tar with GNU long filename extensions, GZip, zlib and raw deflate, as well as BZip2. Zip64 is supported while Deflate64 is not yet supported. It is implemented as an assembly (installable in the GAC), and thus can easily be incorporated into other projects (in any .NET language). The creator of SharpZipLib put it this way: "I've ported the zip library over to C\# because I needed gzip/zip compression and I didn't want to use libzip.dll or something like this. I want all in pure C\#." + +SharpZipLib was originally ported from the [GNU Classpath](http://www.gnu.org/software/classpath/) java.util.zip library for use with [SharpDevelop](http://www.icsharpcode.net/OpenSource/SD), which needed gzip/zip compression. bzip2 compression and tar archiving were added later due to popular demand. + +The [SharpZipLib homepage](http://icsharpcode.github.io/SharpZipLib/) has precompiled libraries available for download, [a link to the forum for support](http://community.sharpdevelop.net/forums/12/ShowForum.aspx), [release history](https://github.com/icsharpcode/SharpZipLib/wiki/Release-History), samples and more. + +License +------- + +This software is now released under the [MIT License](https://opensource.org/licenses/MIT). Please see [issue #103](https://github.com/icsharpcode/SharpZipLib/issues/103) for more information on the relicensing effort. + +Previous versions were released under the [GNU General Public License, version 2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) with an [exception](http://www.gnu.org/software/classpath/license.html) which allowed linking with non-GPL programs. + +Namespace layout +---------------- + +| Module | Namespace | +|:----------------:|:-----------------------------| +|BZip2 implementation|ICSharpCode.SharpZipLib.BZip2.\*| +|Checksum implementation|ICSharpCode.SharpZipLib.Checksums.\*| +|Core utilities / interfaces|ICSharpCode.SharpZipLib.Core.\*| +|Encryption implementation|ICSharpCode.SharpZipLib.Encryption.\*| +|GZip implementation|ICSharpCode.SharpZipLib.GZip.\*| +|LZW implementation|ICSharpCode.SharpZipLib.Lzw.\*| +|Tar implementation|ICSharpCode.SharpZipLib.Tar.\*| +|ZIP implementation|ICSharpCode.SharpZipLib.Zip.\*| +|Inflater/Deflater|ICSharpCode.SharpZipLib.Zip.Compression.\*| +|Inflater/Deflater streams|ICSharpCode.SharpZipLib.Zip.Compression.Streams.\*| + +Credits +------- + +SharpZipLib was initially developed by [Mike Krüger](http://www.icsharpcode.net/pub/relations/krueger.aspx). Past maintainers are John Reilly, David Pierson and Neil McNeight. + +And thanks to all the people that contributed features, bug fixes and issue reports. -\#ziplib is a Zip, GZip, Tar and BZip2 library written entirely in C# for the .NET platform. -Please see the [\#ziplib homepage](http://icsharpcode.github.io/SharpZipLib/) for precompiled downloads, -license information, link to the forum (support), release history, samples and more. **** Kabam Note @@ -13,4 +50,5 @@ target version meta data into the DLL (even project is set to be .net20 compatib which unity does not like - open ICSharpCode.SharpZLib2005.sln and build for "Release" config -- then copy the output dll "./bin/ICSharpCode.SharpZipLib.dll" to unity's "Assets/Plugins/ICSharpCode.SharpZipLib.dll" \ No newline at end of file +- then copy the output dll "./bin/ICSharpCode.SharpZipLib.dll" to unity's "Assets/Plugins/ICSharpCode.SharpZipLib.dll" + diff --git a/Rebracer.xml b/Rebracer.xml new file mode 100644 index 000000000..284eb4a80 --- /dev/null +++ b/Rebracer.xml @@ -0,0 +1,372 @@ + + + + + + + + + + + + + HACK:2 + TODO:2 + UNDONE:2 + UnresolvedMergeConflict:3 + + false + false + false + + + + + 1 + 1 + 1 + 1 + 1 + -1 + -1 + 1 + 2 + 80 + 0 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 0 + 1 + 0 + 0 + 2 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 2 + 1 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + <NamingPreferencesInfo SerializationVersion="4"> + <SymbolSpecifications> + <SymbolSpecification ID="5c545a62-b14d-460a-88d8-e936c0a39316" Name="Class"> + <ApplicableSymbolKindList> + <TypeKind>Class</TypeKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="23d856b4-5089-4405-83ce-749aada99153" Name="Interface"> + <ApplicableSymbolKindList> + <TypeKind>Interface</TypeKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="d1796e78-ff66-463f-8576-eb46416060c0" Name="Struct"> + <ApplicableSymbolKindList> + <TypeKind>Struct</TypeKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="d8af8dc6-1ade-441d-9947-8946922e198a" Name="Enum"> + <ApplicableSymbolKindList> + <TypeKind>Enum</TypeKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="408a3347-b908-4b54-a954-1355e64c1de3" Name="Delegate"> + <ApplicableSymbolKindList> + <TypeKind>Delegate</TypeKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="830657f6-e7e5-4830-b328-f109d3b6c165" Name="Event"> + <ApplicableSymbolKindList> + <SymbolKind>Event</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="390caed4-f0a9-42bb-adbb-b44c4a302a22" Name="Method"> + <ApplicableSymbolKindList> + <SymbolKind>Method</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="af410767-f189-47c6-b140-aeccf1ff242e" Name="Private Method"> + <ApplicableSymbolKindList> + <SymbolKind>Method</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Private</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="8076757e-6a4a-47f1-9b4b-ae8a3284e987" Name="Abstract Method"> + <ApplicableSymbolKindList> + <SymbolKind>Method</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList> + <ModifierKind>IsAbstract</ModifierKind> + </RequiredModifierList> + </SymbolSpecification> + <SymbolSpecification ID="16133061-a8e7-4392-92c3-1d93cd54c218" Name="Static Method"> + <ApplicableSymbolKindList> + <SymbolKind>Method</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList> + <ModifierKind>IsStatic</ModifierKind> + </RequiredModifierList> + </SymbolSpecification> + <SymbolSpecification ID="da6a2919-5aa6-4ad1-a24d-576776ed3974" Name="Property"> + <ApplicableSymbolKindList> + <SymbolKind>Property</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="b24a91ce-3501-4799-b6df-baf044156c83" Name="Public or Protected Field"> + <ApplicableSymbolKindList> + <SymbolKind>Field</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="70af42cb-1741-4027-969c-9edc4877d965" Name="Static Field"> + <ApplicableSymbolKindList> + <SymbolKind>Field</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList> + <ModifierKind>IsStatic</ModifierKind> + </RequiredModifierList> + </SymbolSpecification> + <SymbolSpecification ID="10790aa6-0a0b-432d-a52d-d252ca92302b" Name="Private or Internal Field"> + <ApplicableSymbolKindList> + <SymbolKind>Field</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="ac995be4-88de-4771-9dcc-a456a7c02d89" Name="Private or Internal Static Field"> + <ApplicableSymbolKindList> + <SymbolKind>Field</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList> + <ModifierKind>IsStatic</ModifierKind> + </RequiredModifierList> + </SymbolSpecification> + <SymbolSpecification ID="2c07f5bf-bc81-4c2b-82b4-ae9b3ffd0ba4" Name="Types"> + <ApplicableSymbolKindList> + <TypeKind>Class</TypeKind> + <TypeKind>Struct</TypeKind> + <TypeKind>Interface</TypeKind> + <TypeKind>Enum</TypeKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + <SymbolSpecification ID="5f3ddba1-279f-486c-801e-5c097c36dd85" Name="Non-Field Members"> + <ApplicableSymbolKindList> + <SymbolKind>Property</SymbolKind> + <SymbolKind>Method</SymbolKind> + <SymbolKind>Event</SymbolKind> + </ApplicableSymbolKindList> + <ApplicableAccessibilityList> + <AccessibilityKind>Public</AccessibilityKind> + <AccessibilityKind>Internal</AccessibilityKind> + <AccessibilityKind>Private</AccessibilityKind> + <AccessibilityKind>Protected</AccessibilityKind> + <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> + </ApplicableAccessibilityList> + <RequiredModifierList /> + </SymbolSpecification> + </SymbolSpecifications> + <NamingStyles> + <NamingStyle ID="87e7c501-9948-4b53-b1eb-a6cbe918feee" Name="Pascal Case" Prefix="" Suffix="" WordSeparator="" CapitalizationScheme="PascalCase" /> + <NamingStyle ID="1ecc5eb6-b5fc-49a5-a9f1-a980f3e48c92" Name="Begins with I" Prefix="I" Suffix="" WordSeparator="" CapitalizationScheme="PascalCase" /> + </NamingStyles> + <NamingRules> + <SerializableNamingRule SymbolSpecificationID="23d856b4-5089-4405-83ce-749aada99153" NamingStyleID="1ecc5eb6-b5fc-49a5-a9f1-a980f3e48c92" EnforcementLevel="Info" /> + <SerializableNamingRule SymbolSpecificationID="2c07f5bf-bc81-4c2b-82b4-ae9b3ffd0ba4" NamingStyleID="87e7c501-9948-4b53-b1eb-a6cbe918feee" EnforcementLevel="Info" /> + <SerializableNamingRule SymbolSpecificationID="5f3ddba1-279f-486c-801e-5c097c36dd85" NamingStyleID="87e7c501-9948-4b53-b1eb-a6cbe918feee" EnforcementLevel="Info" /> + </NamingRules> +</NamingPreferencesInfo> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + 1 + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Hidden" /> + 1 + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="true" DiagnosticSeverity="Info" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + 0 + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + <CodeStyleOption SerializationVersion="1" Type="Boolean" Value="false" DiagnosticSeverity="Hidden" /> + 0 + 0 + 1 + 0 + 0 + 1 + 1 + + + + diff --git a/SharpZipAll.sln b/SharpZipAll.sln deleted file mode 100644 index afbc91799..000000000 --- a/SharpZipAll.sln +++ /dev/null @@ -1,72 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpZipLibTests", "tests\SharpZipLibTests.csproj", "{4F9BF21E-A7FC-4005-A1C7-A17108F7010D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZLib", "src\ICSharpCode.SharpZLib.csproj", "{0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sz", "samples\cs\sz\sz.csproj", "{CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zf", "samples\cs\zf\zf.csproj", "{90E83588-261C-45A3-964F-4B707357D437}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CreateZipFile", "samples\vb\CreateZipFile\CreateZipFile.vbproj", "{1B2FD768-E530-45B7-B14F-AE5D07B24485}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "viewzipfile", "samples\vb\viewzipfile\viewzipfile.vbproj", "{DB53264C-64AD-4B43-91A9-F5325561C77B}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "minibzip2", "samples\vb\minibzip2\minibzip2.vbproj", "{E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "zipfiletest", "samples\vb\zipfiletest\zipfiletest.vbproj", "{54057AFD-35E2-48C3-8419-45D57C351C1F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tar", "samples\cs\tar\tar.csproj", "{88B53A25-82F4-406A-920D-163E717F6AB7}" -EndProject -Global - GlobalSection(SubversionScc) = preSolution - Svn-Managed = True - Manager = AnkhSVN - Subversion Support for Visual Studio - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.Build.0 = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.Build.0 = Release|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Release|Any CPU.Build.0 = Release|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Debug|Any CPU.Build.0 = Debug|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Release|Any CPU.ActiveCfg = Release|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Release|Any CPU.Build.0 = Release|Any CPU - {1B2FD768-E530-45B7-B14F-AE5D07B24485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B2FD768-E530-45B7-B14F-AE5D07B24485}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B2FD768-E530-45B7-B14F-AE5D07B24485}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B2FD768-E530-45B7-B14F-AE5D07B24485}.Release|Any CPU.Build.0 = Release|Any CPU - {DB53264C-64AD-4B43-91A9-F5325561C77B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DB53264C-64AD-4B43-91A9-F5325561C77B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DB53264C-64AD-4B43-91A9-F5325561C77B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DB53264C-64AD-4B43-91A9-F5325561C77B}.Release|Any CPU.Build.0 = Release|Any CPU - {E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}.Release|Any CPU.Build.0 = Release|Any CPU - {54057AFD-35E2-48C3-8419-45D57C351C1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {54057AFD-35E2-48C3-8419-45D57C351C1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {54057AFD-35E2-48C3-8419-45D57C351C1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {54057AFD-35E2-48C3-8419-45D57C351C1F}.Release|Any CPU.Build.0 = Release|Any CPU - {88B53A25-82F4-406A-920D-163E717F6AB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {88B53A25-82F4-406A-920D-163E717F6AB7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {88B53A25-82F4-406A-920D-163E717F6AB7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {88B53A25-82F4-406A-920D-163E717F6AB7}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/SharpZipAll2005.sln b/SharpZipAll2005.sln deleted file mode 100644 index 5e39bafb0..000000000 --- a/SharpZipAll2005.sln +++ /dev/null @@ -1,38 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZLib", "src\ICSharpCode.SharpZLib.csproj", "{0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zf", "samples\cs\zf\zf.csproj", "{90E83588-261C-45A3-964F-4B707357D437}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sz", "samples\cs\sz\sz.csproj", "{CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpZipLibTests", "tests\SharpZipLibTests.csproj", "{4F9BF21E-A7FC-4005-A1C7-A17108F7010D}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.Build.0 = Release|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Debug|Any CPU.Build.0 = Debug|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Release|Any CPU.ActiveCfg = Release|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Release|Any CPU.Build.0 = Release|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Release|Any CPU.Build.0 = Release|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/SharpZipAll2008.sln b/SharpZipAll2008.sln deleted file mode 100644 index e64e39d9b..000000000 --- a/SharpZipAll2008.sln +++ /dev/null @@ -1,72 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpZipLibTests", "tests\SharpZipLibTests.csproj", "{4F9BF21E-A7FC-4005-A1C7-A17108F7010D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZLib", "src\ICSharpCode.SharpZLib.csproj", "{0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sz", "samples\cs\sz\sz.csproj", "{CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zf", "samples\cs\zf\zf.csproj", "{90E83588-261C-45A3-964F-4B707357D437}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CreateZipFile", "samples\vb\CreateZipFile\CreateZipFile.vbproj", "{1B2FD768-E530-45B7-B14F-AE5D07B24485}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "viewzipfile", "samples\vb\viewzipfile\viewzipfile.vbproj", "{DB53264C-64AD-4B43-91A9-F5325561C77B}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "minibzip2", "samples\vb\minibzip2\minibzip2.vbproj", "{E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "zipfiletest", "samples\vb\zipfiletest\zipfiletest.vbproj", "{54057AFD-35E2-48C3-8419-45D57C351C1F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tar", "samples\cs\tar\Tar.csproj", "{12C2AD0C-B815-426D-AFF1-7787C2DCA0F0}" -EndProject -Global - GlobalSection(SubversionScc) = preSolution - Svn-Managed = True - Manager = AnkhSVN - Subversion Support for Visual Studio - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4F9BF21E-A7FC-4005-A1C7-A17108F7010D}.Release|Any CPU.Build.0 = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Release|Any CPU.Build.0 = Release|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE0CEA62-CC91-4D17-BC57-A5FCACCA6A1F}.Release|Any CPU.Build.0 = Release|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Debug|Any CPU.Build.0 = Debug|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Release|Any CPU.ActiveCfg = Release|Any CPU - {90E83588-261C-45A3-964F-4B707357D437}.Release|Any CPU.Build.0 = Release|Any CPU - {1B2FD768-E530-45B7-B14F-AE5D07B24485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B2FD768-E530-45B7-B14F-AE5D07B24485}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B2FD768-E530-45B7-B14F-AE5D07B24485}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B2FD768-E530-45B7-B14F-AE5D07B24485}.Release|Any CPU.Build.0 = Release|Any CPU - {DB53264C-64AD-4B43-91A9-F5325561C77B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DB53264C-64AD-4B43-91A9-F5325561C77B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DB53264C-64AD-4B43-91A9-F5325561C77B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DB53264C-64AD-4B43-91A9-F5325561C77B}.Release|Any CPU.Build.0 = Release|Any CPU - {E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4AFB41C-DDBB-44AD-9D64-304B7FEE66C9}.Release|Any CPU.Build.0 = Release|Any CPU - {54057AFD-35E2-48C3-8419-45D57C351C1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {54057AFD-35E2-48C3-8419-45D57C351C1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {54057AFD-35E2-48C3-8419-45D57C351C1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {54057AFD-35E2-48C3-8419-45D57C351C1F}.Release|Any CPU.Build.0 = Release|Any CPU - {12C2AD0C-B815-426D-AFF1-7787C2DCA0F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {12C2AD0C-B815-426D-AFF1-7787C2DCA0F0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {12C2AD0C-B815-426D-AFF1-7787C2DCA0F0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {12C2AD0C-B815-426D-AFF1-7787C2DCA0F0}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/SharpZipLib.shfb b/SharpZipLib.shfb deleted file mode 100644 index 9588e2818..000000000 --- a/SharpZipLib.shfb +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - The root namespace for this library. - BZip2 compression handling - Checksum Handling - Core Utilities - Encryption handling - GZip compression handling - Tape Archive handling - ZIP archive handling - Zip Compression handling - Zip compression streams. - - Welcome to the #Zip compression library! - Summary, Parameter, Returns, AutoDocumentCtors, Namespace - InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - - - C:\Common\User\John\Development\SharpZipLib\trunk\SharpZipLib\current\doc\ - - - True - True - HtmlHelp1x - True - False - 2.0.50727 - True - False - False - False - - ICSharpCode.SharpZipLib Compression Library - SharpZipLib - en-US - - - - - - Local - Msdn - Blank - Prototype - Guid - Standard - False - AboveNamespaces - - - \ No newline at end of file diff --git a/SharpZlib.build b/SharpZlib.build deleted file mode 100644 index 3f5aceaca..000000000 --- a/SharpZlib.build +++ /dev/null @@ -1,346 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/appveyor.yml.old b/appveyor.yml.old new file mode 100644 index 000000000..5b4b16d31 --- /dev/null +++ b/appveyor.yml.old @@ -0,0 +1,94 @@ +version: 1.0.{build} +branches: + only: + - master + except: + - gh-pages + - coverity_scan + +skip_tags: true +image: Visual Studio 2017 + +init: + - git config --global core.autocrlf input + +cache: + - packages -> **\packages.config + +assembly_info: + patch: true + file: 'src\**\AssemblyInfo.cs' + assembly_version: '{version}' + assembly_file_version: '{version}' + assembly_informational_version: '{version}' + +nuget: + account_feed: true + project_feed: true + disable_publish_on_pr: true + +configuration: Release + +environment: + COVERALLS_REPO_TOKEN: + secure: B/NQfoRYUnKLGS5KJSJrGBvcYD0Jv+coudjJMY2jf+gqvqDWral9CDmv2i0WovY7 + COVERITY_TOKEN: + secure: n9NA/kasTqxUc8UBfQ2cBlZcDyFJvko1gcMzVTDvZq8= + COVERITY_EMAIL: + secure: j/N0ZmnUZYKnS2nGocKyNsXoKQBfWTBOg+VI4q7yMn4= + +before_build: +- dotnet restore ICSharpCode.SharpZipLib.sln + +build_script: +- ps: Build\run-appveyor-build.ps1 + +test_script: + - dotnet test test\ICSharpCode.SharpZipLib.Tests + +after_test: + - cmd: Build\run-opencover.cmd + - cmd: packages\coveralls.io.1.3.4\tools\coveralls.net.exe --opencover Documentation\opencover-results-release.xml + - cmd: nuget pack Build\ICSharpCode.SharpZipLib.nuspec -BasePath bin\Release\ -OutputDirectory bin\Release\ -Version %APPVEYOR_BUILD_VERSION% + +test_script: + - cmd: nunit3-console --framework=net-4.5 --labels=All --testlist=ICSharpCode.SharpZipLib.Tests\PassingTests.txt --result=Documentation\nunit3-test-results-appveyor.xml;format=AppVeyor bin\Release\ICSharpCode.SharpZipLib.Tests.dll + +artifacts: +- path: bin\Release + name: BuildRelease +- path: bin\**\*.nupkg + name: NuGet +- path: Documentation\*.xml + name: TestResults +- path: Documentation\coverity.zip + name: Coverity + +deploy: +- provider: GitHub + release: sharpziplib-dogfood-{version} + description: 'Something To Eat' + auth_token: + secure: pZ5zHJ/2mZsmqQH0gPke0LMqSgUhz79wbcCjdDTCEIl6hRJYlYhkaPianw2hz26k # your encrypted token from GitHub + artifact: BuildRelease + draft: true + prerelease: true + on: + branch: master +# appveyor_repo_tag: true # deploy on tag push only +- provider: NuGet + skip_symbols: false + symbol_server: https://ci.appveyor.com/nuget/mcneight-93sw9hg8ve02/api/v2/package + api_key: + secure: z+iy8Iv5qqQghGrATRbx2I921HCHD7x7/xIrmkGGauMgpA/d1DBoOVUNNCHLE9Dj + artifact: NuGet + +notifications: +- provider: Email + to: + - mcneight+appveyor@gmail.com + subject: Build {{status}} + message: Version {{version}} {{commitId}} from {{branch}} {{status}} {{message}} + on_build_success: true + on_build_failure: true + on_build_status_changed: true \ No newline at end of file diff --git a/build.bat b/build.bat deleted file mode 100644 index c243bc642..000000000 --- a/build.bat +++ /dev/null @@ -1,4 +0,0 @@ -@ECHO OFF -@REM Note you need to set up the path to nant on your machine. -nant -IF %ERRORLEVEL% NEQ 0 PAUSE diff --git a/doc/COPYING.txt b/doc/COPYING.txt deleted file mode 100644 index 5b6e7c66c..000000000 --- a/doc/COPYING.txt +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/doc/ReadMe.rtf b/doc/ReadMe.rtf deleted file mode 100644 index 25c80149b..000000000 --- a/doc/ReadMe.rtf +++ /dev/null @@ -1,99 +0,0 @@ -{\rtf1\ansi\deff1\adeflang1025 -{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\fswiss\fprq0\fcharset0 ArialMT;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Times New Roman;}{\f4\froman\fprq2\fcharset128 Times New Roman;}{\f5\fnil\fprq0\fcharset0 Arial-BoldMT;}{\f6\fnil\fprq0\fcharset0 TimesNewRomanPS-BoldMT;}{\f7\fswiss\fprq0\fcharset0 ArialMT;}{\f8\fnil\fprq2\fcharset0 Arial Unicode MS;}{\f9\fnil\fprq2\fcharset0 Tahoma;}{\f10\fnil\fprq0\fcharset0 Tahoma;}} -{\colortbl;\red0\green0\blue0;\red0\green0\blue129;\red0\green0\blue128;\red0\green0\blue255;\red128\green128\blue128;\red51\green0\blue51;} -{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033\snext1 Normal;} -{\s2\sb240\sa120\keepn\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af9\afs28\lang1033\ltrch\dbch\af8\langfe1033\hich\f2\fs28\lang1033\loch\f2\fs28\lang1033\sbasedon1\snext3 Heading;} -{\s3\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033\sbasedon1\snext3 Body Text;} -{\s4\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af10\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033\sbasedon3\snext4 List;} -{\s5\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af10\afs24\lang1033\ai\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\i\loch\f1\fs24\lang1033\i\sbasedon1\snext5 caption;} -{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af10\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033\sbasedon1\snext6 Index;} -{\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033\sbasedon1\snext7 Table Contents;} -{\s8\cf0\qc{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ab\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\b\loch\f1\fs24\lang1033\b\sbasedon7\snext8 Table Heading;} -{\*\cs10\cf3\ul\ulc0\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 Internet link;} -} -{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment StarWriter}{\vern6800}}\deftab709 -{\*\pgdsctbl -{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1800\margrsxn1800\margtsxn1440\margbsxn1440\pgdscnxt0 Standard;}} -{\*\pgdscno0}\paperh15840\paperw12240\margl1800\margr1800\margt1440\margb1440\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1800\margrsxn1800\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc -\pard\plain \ltrpar\s1\cf0\qc{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\fs44\lang5129\loch\fs44\lang5129 #ZipLib}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f4\lang1041\loch\f4\lang1041 }} -\par \pard\plain \ltrpar\s1\cf0\qc{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch \~ } -\par \pard\plain \ltrpar\s1\cf0\qc{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Version 0.85.5}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f5\fs32\lang5129\b\loch\f5\fs32\lang5129\b Introduction}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f4\lang1041\loch\f4\lang1041 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch } -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\loch\f0 #ZipLib is a }}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\b\loch\f0\b Zip, GZip, Tar and BZip2 library}{\rtlch\ltrch\dbch\hich\f0\loch\f0 written entirely in C# for the .NET framework. It is implemented as an assembly (installable in the GAC), and can easily be incorporated into other projects using any .NET language.}} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\loch\f0 #ZipLib was ported from the GNU Classpath ZIP library for use with #Develop (}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\field{\*\fldinst HYPERLINK "http://www.icsharpcode.net/OpenSource/SD" }{\fldrslt \*\cs10\cf3\ul\ulc0\rtlch\ltrch\dbch\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch\ltrch\dbch\hich\f0\loch\f0 http://www.icsharpcode.net/OpenSource/SD}}}{\cf1\rtlch\ltrch\dbch\hich\f0\loch\f0 ) which needed gzip/zip compression. Later bzip2 compression and tar archiving was added due to popular demand.}{\rtlch\ltrch\dbch\hich\f0\loch\f0 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch } -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 There is a web site from which you can download the assembly and or the source code (}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\field{\*\fldinst HYPERLINK "http://icsharpcode.net/OpenSource/SharpZipLib" }{\fldrslt \*\cs10\cf3\ul\ulc0\rtlch\ltrch\dbch\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch\ltrch\dbch\hich\f0\loch\f0 http://icsharpcode.net/OpenSource/SharpZipLib}}}{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 ). A forum is also available at }{\rtlch\ltrch\dbch\hich\f0\loch\f0 http://community.sharpdevelop.net/forums/12/ShowForum.aspx}{\rtlch\ltrch\dbch\hich\f4\lang1041\loch\f4\lang1041 .}} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f5\fs32\lang5129\b\loch\f5\fs32\lang5129\b License}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f4\lang1041\loch\f4\lang1041 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 The software is released under the GPL with an exception which allows linking with non GPL programs. The exception to the GPL is as follows:}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License cover the whole combination.}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting - executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library.}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang5129\loch\f0\fs24\lang5129 {\rtlch \ltrch\loch\f0\fs24\lang5129\i0\b0 \line \~ } -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f6\fs32\lang5129\b\loch\f6\fs32\lang5129\b Building the library}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Currently there are two ways to build this library :}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\b\loch\f0\lang5129\b NAnt }}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 (}{\cf2\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 http://nant.sourceforge.net}{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 )}{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 This is a free makefile replacement, I encourage the use of this free build automation}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 utility. Just run the SharpZiplib.build in the src directory. (see the nant documentation}{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 for more information about nant).}{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Version 0.85 was used during development. }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\b\loch\f0\lang5129\b SharpDevelop }}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 (}{\cf2\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 http://www.icsharpcode.net/OpenSource/SD}{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 )}{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 This is a free IDE for .NET, the projects are available in the sourece and samples download. Give it a try.}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang5129\loch\f0\fs24\lang5129 {\rtlch \ltrch\loch\f0\fs24\lang5129\i0\b0 \line } -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f6\fs32\lang5129\b\loch\f6\fs32\lang5129\b Namespace Layout}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f4\lang1041\loch\f4\lang1041 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch } -\par \trowd\trql\trleft-10\trpaddft3\trpaddt0\trpaddfl3\trpaddl10\trpaddfb3\trpaddb0\trpaddfr3\trpaddr10\clbrdrt\brdrs\brdrw20\brdrcf6\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clvertalc\cellx4233\clbrdrt\brdrs\brdrw20\brdrcf6\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clbrdrr\brdrs\brdrw20\brdrcf6\clvertalc\cellx8640 -\pard\intbl\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Zip implementation}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\loch\f0 }} -\cell\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 ICSharpCode.SharpZipLib.Zip } -\cell\row\pard \trowd\trql\trleft-10\trpaddft3\trpaddt0\trpaddfl3\trpaddl10\trpaddfb3\trpaddb0\trpaddfr3\trpaddr10\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clvertalc\cellx4233\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clbrdrr\brdrs\brdrw20\brdrcf6\clvertalc\cellx8640 -\pard\intbl\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Tar implementation}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\loch\f0 }} -\cell\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 ICSharpCode.SharpZipLib.Tar.*}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\loch\f0 }} -\cell\row\pard \trowd\trql\trpaddft3\trpaddt0\trpaddfl3\trpaddl10\trpaddfb3\trpaddb0\trpaddfr3\trpaddr10\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clvertalc\cellx4238\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clbrdrr\brdrs\brdrw20\brdrcf6\clvertalc\cellx8640 -\pard\intbl\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Gzip implementation}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\loch\f0 }} -\cell\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 ICSharpCode.SharpZipLib.GZip.* } -\cell\row\pard \trowd\trql\trpaddft3\trpaddt0\trpaddfl3\trpaddl10\trpaddfb3\trpaddb0\trpaddfr3\trpaddr10\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clvertalc\cellx4238\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clbrdrr\brdrs\brdrw20\brdrcf6\clvertalc\cellx8640 -\pard\intbl\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Bzip2 implementation}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\loch\f0 }} -\cell\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 ICSharpCode.SharpZipLib.BZip2.* } -\cell\row\pard \trowd\trql\trpaddft3\trpaddt0\trpaddfl3\trpaddl10\trpaddfb3\trpaddb0\trpaddfr3\trpaddr10\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clvertalc\cellx4238\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clbrdrr\brdrs\brdrw20\brdrcf6\clvertalc\cellx8640 -\pard\intbl\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Inflater/Deflater streams}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\loch\f0 }} -\cell\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 ICSharpCode.SharpZipLib.Zip.Compression.Streams } -\cell\row\pard \trowd\trql\trleft-10\trpaddft3\trpaddt0\trpaddfl3\trpaddl10\trpaddfb3\trpaddb0\trpaddfr3\trpaddr10\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clvertalc\cellx4233\clbrdrl\brdrs\brdrw20\brdrcf6\clbrdrb\brdrs\brdrw20\brdrcf6\clbrdrr\brdrs\brdrw20\brdrcf6\clvertalc\cellx8640 -\pard\intbl\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Core utilities /\~interfaces } -\cell\pard\plain \intbl\ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 ICSharCode.SharpZipLib.Core } -\cell\row\pard \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch \~ } -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283 {\rtlch \ltrch\loch \~ } -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f6\fs32\lang5129\b\loch\f6\fs32\lang5129\b Reporting Bugs/Submit Patches}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f4\lang1041\loch\f4\lang1041 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 If you want to submit a patch write to }}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf2\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 mike@icsharpcode.net}{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 . If it is a bug fix then it is required that you write a unit test demonstrating the bug. If you find a bug send me a case (generally a file that fails) or preferably a unit test demonstrating the - bug. I'll try to fix it.}{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f6\fs32\lang5129\b\loch\f6\fs32\lang5129\b Credits}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f4\lang1041\loch\f4\lang1041 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 #ZipLib\~was originally\~developed by Mike Krueger (}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\field{\*\fldinst HYPERLINK "mailto:mike@icsharpcode.net" }{\fldrslt \*\cs10\cf3\ul\ulc0\rtlch\ltrch\dbch\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\cf3\ul\ulc0\rtlch\ltrch\dbch\hich\f0\loch\f0 mike@icsharpcode.net}}}{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 ). However, much existing Java code helped a lot in speeding the creation of this library. }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch \~ } -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Therefore credits fly out to others.}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Zip/Gzip implementation :}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 A Java version of the zlib which was originally created by the Free Software Foundation (FSF). So all credits should go to the FSF and the authors who have worked on this piece of code.}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Without the zlib authors the Java zlib wouldn't be possible :}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Jean-loup Gailly(jloup@gzip.org)}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Mark Adler(}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\field{\*\fldinst HYPERLINK "mailto:madler@alumni.caltech.edu" }{\fldrslt \*\cs10\cf3\ul\ulc0\rtlch\ltrch\dbch\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\cf4\ul\ulc0\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 madler@alumni.caltech.edu}}}{\cf1\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 ) and contributors of zlib.}{\rtlch\ltrch\dbch\hich\f0\lang3081\loch\f0\lang3081 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 For the bzip2 implementation :}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Julian R Seward}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 The Java port was done by Keiron Liddle, Aftex Software(keiron@aftexsw.com)}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Credits for the tar implementation fly out to :}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Timothy Gerard Endres(time@gjt.org)}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af1\afs24\lang1033\ltrch\dbch\af1\langfe1033\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\cf1\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 Special thanks to Christoph Wille for beta testing, suggestions and the setup of the Web site.}}{\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0{\rtlch\ltrch\dbch\hich\f0\lang5129\loch\f0\lang5129 }} -\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\sa283\rtlch\af0\afs24\lang1033\ltrch\dbch\af0\langfe1033\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 -\par } \ No newline at end of file diff --git a/doc/specification/appnote.txt b/doc/specification/appnote.txt deleted file mode 100644 index 1565e775b..000000000 --- a/doc/specification/appnote.txt +++ /dev/null @@ -1,3217 +0,0 @@ -File: APPNOTE.TXT - .ZIP File Format Specification -Version: 6.3.2 -Revised: September 28, 2007 -Copyright (c) 1989 - 2007 PKWARE Inc., All Rights Reserved. - -The use of certain technological aspects disclosed in the current -APPNOTE is available pursuant to the below section entitled -"Incorporating PKWARE Proprietary Technology into Your Product". - -I. Purpose ----------- - -This specification is intended to define a cross-platform, -interoperable file storage and transfer format. Since its -first publication in 1989, PKWARE has remained committed to -ensuring the interoperability of the .ZIP file format through -publication and maintenance of this specification. We trust that -all .ZIP compatible vendors and application developers that have -adopted and benefited from this format will share and support -this commitment to interoperability. - -II. Contacting PKWARE ---------------------- - - PKWARE, Inc. - 648 N. Plankinton Avenue, Suite 220 - Milwaukee, WI 53203 - +1-414-289-9788 - +1-414-289-9789 FAX - zipformat@pkware.com - -III. Disclaimer ---------------- - -Although PKWARE will attempt to supply current and accurate -information relating to its file formats, algorithms, and the -subject programs, the possibility of error or omission cannot -be eliminated. PKWARE therefore expressly disclaims any warranty -that the information contained in the associated materials relating -to the subject programs and/or the format of the files created or -accessed by the subject programs and/or the algorithms used by -the subject programs, or any other matter, is current, correct or -accurate as delivered. Any risk of damage due to any possible -inaccurate information is assumed by the user of the information. -Furthermore, the information relating to the subject programs -and/or the file formats created or accessed by the subject -programs and/or the algorithms used by the subject programs is -subject to change without notice. - -If the version of this file is marked as a NOTIFICATION OF CHANGE, -the content defines an Early Feature Specification (EFS) change -to the .ZIP file format that may be subject to modification prior -to publication of the Final Feature Specification (FFS). This -document may also contain information on Planned Feature -Specifications (PFS) defining recognized future extensions. - -IV. Change Log --------------- - -Version Change Description Date -------- ------------------ ---------- -5.2 -Single Password Symmetric Encryption 06/02/2003 - storage - -6.1.0 -Smartcard compatibility 01/20/2004 - -Documentation on certificate storage - -6.2.0 -Introduction of Central Directory 04/26/2004 - Encryption for encrypting metadata - -Added OS/X to Version Made By values - -6.2.1 -Added Extra Field placeholder for 04/01/2005 - POSZIP using ID 0x4690 - - -Clarified size field on - "zip64 end of central directory record" - -6.2.2 -Documented Final Feature Specification 01/06/2006 - for Strong Encryption - - -Clarifications and typographical - corrections - -6.3.0 -Added tape positioning storage 09/29/2006 - parameters - - -Expanded list of supported hash algorithms - - -Expanded list of supported compression - algorithms - - -Expanded list of supported encryption - algorithms - - -Added option for Unicode filename - storage - - -Clarifications for consistent use - of Data Descriptor records - - -Added additional "Extra Field" - definitions - -6.3.1 -Corrected standard hash values for 04/11/2007 - SHA-256/384/512 - -6.3.2 -Added compression method 97 09/28/2007 - - -Documented InfoZIP "Extra Field" - values for UTF-8 file name and - file comment storage - -V. General Format of a .ZIP file --------------------------------- - - Files stored in arbitrary order. Large .ZIP files can span multiple - volumes or be split into user-defined segment sizes. All values - are stored in little-endian byte order unless otherwise specified. - - Overall .ZIP file format: - - [local file header 1] - [file data 1] - [data descriptor 1] - . - . - . - [local file header n] - [file data n] - [data descriptor n] - [archive decryption header] - [archive extra data record] - [central directory] - [zip64 end of central directory record] - [zip64 end of central directory locator] - [end of central directory record] - - - A. Local file header: - - local file header signature 4 bytes (0x04034b50) - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - file name length 2 bytes - extra field length 2 bytes - - file name (variable size) - extra field (variable size) - - B. File data - - Immediately following the local header for a file - is the compressed or stored data for the file. - The series of [local file header][file data][data - descriptor] repeats for each file in the .ZIP archive. - - C. Data descriptor: - - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - - This descriptor exists only if bit 3 of the general - purpose bit flag is set (see below). It is byte aligned - and immediately follows the last byte of compressed data. - This descriptor is used only when it was not possible to - seek in the output .ZIP file, e.g., when the output .ZIP file - was standard output or a non-seekable device. For ZIP64(tm) format - archives, the compressed and uncompressed sizes are 8 bytes each. - - When compressing files, compressed and uncompressed sizes - should be stored in ZIP64 format (as 8 byte values) when a - files size exceeds 0xFFFFFFFF. However ZIP64 format may be - used regardless of the size of a file. When extracting, if - the zip64 extended information extra field is present for - the file the compressed and uncompressed sizes will be 8 - byte values. - - Although not originally assigned a signature, the value - 0x08074b50 has commonly been adopted as a signature value - for the data descriptor record. Implementers should be - aware that ZIP files may be encountered with or without this - signature marking data descriptors and should account for - either case when reading ZIP files to ensure compatibility. - When writing ZIP files, it is recommended to include the - signature value marking the data descriptor record. When - the signature is used, the fields currently defined for - the data descriptor record will immediately follow the - signature. - - An extensible data descriptor will be released in a future - version of this APPNOTE. This new record is intended to - resolve conflicts with the use of this record going forward, - and to provide better support for streamed file processing. - - When the Central Directory Encryption method is used, the data - descriptor record is not required, but may be used. If present, - and bit 3 of the general purpose bit field is set to indicate - its presence, the values in fields of the data descriptor - record should be set to binary zeros. - - D. Archive decryption header: - - The Archive Decryption Header is introduced in version 6.2 - of the ZIP format specification. This record exists in support - of the Central Directory Encryption Feature implemented as part of - the Strong Encryption Specification as described in this document. - When the Central Directory Structure is encrypted, this decryption - header will precede the encrypted data segment. The encrypted - data segment will consist of the Archive extra data record (if - present) and the encrypted Central Directory Structure data. - The format of this data record is identical to the Decryption - header record preceding compressed file data. If the central - directory structure is encrypted, the location of the start of - this data record is determined using the Start of Central Directory - field in the Zip64 End of Central Directory record. Refer to the - section on the Strong Encryption Specification for information - on the fields used in the Archive Decryption Header record. - - - E. Archive extra data record: - - archive extra data signature 4 bytes (0x08064b50) - extra field length 4 bytes - extra field data (variable size) - - The Archive Extra Data Record is introduced in version 6.2 - of the ZIP format specification. This record exists in support - of the Central Directory Encryption Feature implemented as part of - the Strong Encryption Specification as described in this document. - When present, this record immediately precedes the central - directory data structure. The size of this data record will be - included in the Size of the Central Directory field in the - End of Central Directory record. If the central directory structure - is compressed, but not encrypted, the location of the start of - this data record is determined using the Start of Central Directory - field in the Zip64 End of Central Directory record. - - - F. Central directory structure: - - [file header 1] - . - . - . - [file header n] - [digital signature] - - File header: - - central file header signature 4 bytes (0x02014b50) - version made by 2 bytes - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - file name length 2 bytes - extra field length 2 bytes - file comment length 2 bytes - disk number start 2 bytes - internal file attributes 2 bytes - external file attributes 4 bytes - relative offset of local header 4 bytes - - file name (variable size) - extra field (variable size) - file comment (variable size) - - Digital signature: - - header signature 4 bytes (0x05054b50) - size of data 2 bytes - signature data (variable size) - - With the introduction of the Central Directory Encryption - feature in version 6.2 of this specification, the Central - Directory Structure may be stored both compressed and encrypted. - Although not required, it is assumed when encrypting the - Central Directory Structure, that it will be compressed - for greater storage efficiency. Information on the - Central Directory Encryption feature can be found in the section - describing the Strong Encryption Specification. The Digital - Signature record will be neither compressed nor encrypted. - - G. Zip64 end of central directory record - - zip64 end of central dir - signature 4 bytes (0x06064b50) - size of zip64 end of central - directory record 8 bytes - version made by 2 bytes - version needed to extract 2 bytes - number of this disk 4 bytes - number of the disk with the - start of the central directory 4 bytes - total number of entries in the - central directory on this disk 8 bytes - total number of entries in the - central directory 8 bytes - size of the central directory 8 bytes - offset of start of central - directory with respect to - the starting disk number 8 bytes - zip64 extensible data sector (variable size) - - The value stored into the "size of zip64 end of central - directory record" should be the size of the remaining - record and should not include the leading 12 bytes. - - Size = SizeOfFixedFields + SizeOfVariableData - 12. - - The above record structure defines Version 1 of the - zip64 end of central directory record. Version 1 was - implemented in versions of this specification preceding - 6.2 in support of the ZIP64 large file feature. The - introduction of the Central Directory Encryption feature - implemented in version 6.2 as part of the Strong Encryption - Specification defines Version 2 of this record structure. - Refer to the section describing the Strong Encryption - Specification for details on the version 2 format for - this record. - - Special purpose data may reside in the zip64 extensible data - sector field following either a V1 or V2 version of this - record. To ensure identification of this special purpose data - it must include an identifying header block consisting of the - following: - - Header ID - 2 bytes - Data Size - 4 bytes - - The Header ID field indicates the type of data that is in the - data block that follows. - - Data Size identifies the number of bytes that follow for this - data block type. - - Multiple special purpose data blocks may be present, but each - must be preceded by a Header ID and Data Size field. Current - mappings of Header ID values supported in this field are as - defined in APPENDIX C. - - H. Zip64 end of central directory locator - - zip64 end of central dir locator - signature 4 bytes (0x07064b50) - number of the disk with the - start of the zip64 end of - central directory 4 bytes - relative offset of the zip64 - end of central directory record 8 bytes - total number of disks 4 bytes - - I. End of central directory record: - - end of central dir signature 4 bytes (0x06054b50) - number of this disk 2 bytes - number of the disk with the - start of the central directory 2 bytes - total number of entries in the - central directory on this disk 2 bytes - total number of entries in - the central directory 2 bytes - size of the central directory 4 bytes - offset of start of central - directory with respect to - the starting disk number 4 bytes - .ZIP file comment length 2 bytes - .ZIP file comment (variable size) - - J. Explanation of fields: - - version made by (2 bytes) - - The upper byte indicates the compatibility of the file - attribute information. If the external file attributes - are compatible with MS-DOS and can be read by PKZIP for - DOS version 2.04g then this value will be zero. If these - attributes are not compatible, then this value will - identify the host system on which the attributes are - compatible. Software can use this information to determine - the line record format for text files etc. The current - mappings are: - - 0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems) - 1 - Amiga 2 - OpenVMS - 3 - UNIX 4 - VM/CMS - 5 - Atari ST 6 - OS/2 H.P.F.S. - 7 - Macintosh 8 - Z-System - 9 - CP/M 10 - Windows NTFS - 11 - MVS (OS/390 - Z/OS) 12 - VSE - 13 - Acorn Risc 14 - VFAT - 15 - alternate MVS 16 - BeOS - 17 - Tandem 18 - OS/400 - 19 - OS/X (Darwin) 20 thru 255 - unused - - The lower byte indicates the ZIP specification version - (the version of this document) supported by the software - used to encode the file. The value/10 indicates the major - version number, and the value mod 10 is the minor version - number. - - version needed to extract (2 bytes) - - The minimum supported ZIP specification version needed to - extract the file, mapped as above. This value is based on - the specific format features a ZIP program must support to - be able to extract the file. If multiple features are - applied to a file, the minimum version should be set to the - feature having the highest value. New features or feature - changes affecting the published format specification will be - implemented using higher version numbers than the last - published value to avoid conflict. - - Current minimum feature versions are as defined below: - - 1.0 - Default value - 1.1 - File is a volume label - 2.0 - File is a folder (directory) - 2.0 - File is compressed using Deflate compression - 2.0 - File is encrypted using traditional PKWARE encryption - 2.1 - File is compressed using Deflate64(tm) - 2.5 - File is compressed using PKWARE DCL Implode - 2.7 - File is a patch data set - 4.5 - File uses ZIP64 format extensions - 4.6 - File is compressed using BZIP2 compression* - 5.0 - File is encrypted using DES - 5.0 - File is encrypted using 3DES - 5.0 - File is encrypted using original RC2 encryption - 5.0 - File is encrypted using RC4 encryption - 5.1 - File is encrypted using AES encryption - 5.1 - File is encrypted using corrected RC2 encryption** - 5.2 - File is encrypted using corrected RC2-64 encryption** - 6.1 - File is encrypted using non-OAEP key wrapping*** - 6.2 - Central directory encryption - 6.3 - File is compressed using LZMA - 6.3 - File is compressed using PPMd+ - 6.3 - File is encrypted using Blowfish - 6.3 - File is encrypted using Twofish - - - * Early 7.x (pre-7.2) versions of PKZIP incorrectly set the - version needed to extract for BZIP2 compression to be 50 - when it should have been 46. - - ** Refer to the section on Strong Encryption Specification - for additional information regarding RC2 corrections. - - *** Certificate encryption using non-OAEP key wrapping is the - intended mode of operation for all versions beginning with 6.1. - Support for OAEP key wrapping should only be used for - backward compatibility when sending ZIP files to be opened by - versions of PKZIP older than 6.1 (5.0 or 6.0). - - + Files compressed using PPMd should set the version - needed to extract field to 6.3, however, not all ZIP - programs enforce this and may be unable to decompress - data files compressed using PPMd if this value is set. - - When using ZIP64 extensions, the corresponding value in the - zip64 end of central directory record should also be set. - This field should be set appropriately to indicate whether - Version 1 or Version 2 format is in use. - - general purpose bit flag: (2 bytes) - - Bit 0: If set, indicates that the file is encrypted. - - (For Method 6 - Imploding) - Bit 1: If the compression method used was type 6, - Imploding, then this bit, if set, indicates - an 8K sliding dictionary was used. If clear, - then a 4K sliding dictionary was used. - Bit 2: If the compression method used was type 6, - Imploding, then this bit, if set, indicates - 3 Shannon-Fano trees were used to encode the - sliding dictionary output. If clear, then 2 - Shannon-Fano trees were used. - - (For Methods 8 and 9 - Deflating) - Bit 2 Bit 1 - 0 0 Normal (-en) compression option was used. - 0 1 Maximum (-exx/-ex) compression option was used. - 1 0 Fast (-ef) compression option was used. - 1 1 Super Fast (-es) compression option was used. - - (For Method 14 - LZMA) - Bit 1: If the compression method used was type 14, - LZMA, then this bit, if set, indicates - an end-of-stream (EOS) marker is used to - mark the end of the compressed data stream. - If clear, then an EOS marker is not present - and the compressed data size must be known - to extract. - - Note: Bits 1 and 2 are undefined if the compression - method is any other. - - Bit 3: If this bit is set, the fields crc-32, compressed - size and uncompressed size are set to zero in the - local header. The correct values are put in the - data descriptor immediately following the compressed - data. (Note: PKZIP version 2.04g for DOS only - recognizes this bit for method 8 compression, newer - versions of PKZIP recognize this bit for any - compression method.) - - Bit 4: Reserved for use with method 8, for enhanced - deflating. - - Bit 5: If this bit is set, this indicates that the file is - compressed patched data. (Note: Requires PKZIP - version 2.70 or greater) - - Bit 6: Strong encryption. If this bit is set, you should - set the version needed to extract value to at least - 50 and you must also set bit 0. If AES encryption - is used, the version needed to extract value must - be at least 51. - - Bit 7: Currently unused. - - Bit 8: Currently unused. - - Bit 9: Currently unused. - - Bit 10: Currently unused. - - Bit 11: Language encoding flag (EFS). If this bit is set, - the filename and comment fields for this file - must be encoded using UTF-8. (see APPENDIX D) - - Bit 12: Reserved by PKWARE for enhanced compression. - - Bit 13: Used when encrypting the Central Directory to indicate - selected data values in the Local Header are masked to - hide their actual values. See the section describing - the Strong Encryption Specification for details. - - Bit 14: Reserved by PKWARE. - - Bit 15: Reserved by PKWARE. - - compression method: (2 bytes) - - (see accompanying documentation for algorithm - descriptions) - - 0 - The file is stored (no compression) - 1 - The file is Shrunk - 2 - The file is Reduced with compression factor 1 - 3 - The file is Reduced with compression factor 2 - 4 - The file is Reduced with compression factor 3 - 5 - The file is Reduced with compression factor 4 - 6 - The file is Imploded - 7 - Reserved for Tokenizing compression algorithm - 8 - The file is Deflated - 9 - Enhanced Deflating using Deflate64(tm) - 10 - PKWARE Data Compression Library Imploding (old IBM TERSE) - 11 - Reserved by PKWARE - 12 - File is compressed using BZIP2 algorithm - 13 - Reserved by PKWARE - 14 - LZMA (EFS) - 15 - Reserved by PKWARE - 16 - Reserved by PKWARE - 17 - Reserved by PKWARE - 18 - File is compressed using IBM TERSE (new) - 19 - IBM LZ77 z Architecture (PFS) - 97 - WavPack compressed data - 98 - PPMd version I, Rev 1 - - date and time fields: (2 bytes each) - - The date and time are encoded in standard MS-DOS format. - If input came from standard input, the date and time are - those at which compression was started for this data. - If encrypting the central directory and general purpose bit - flag 13 is set indicating masking, the value stored in the - Local Header will be zero. - - CRC-32: (4 bytes) - - The CRC-32 algorithm was generously contributed by - David Schwaderer and can be found in his excellent - book "C Programmers Guide to NetBIOS" published by - Howard W. Sams & Co. Inc. The 'magic number' for - the CRC is 0xdebb20e3. The proper CRC pre and post - conditioning is used, meaning that the CRC register - is pre-conditioned with all ones (a starting value - of 0xffffffff) and the value is post-conditioned by - taking the one's complement of the CRC residual. - If bit 3 of the general purpose flag is set, this - field is set to zero in the local header and the correct - value is put in the data descriptor and in the central - directory. When encrypting the central directory, if the - local header is not in ZIP64 format and general purpose - bit flag 13 is set indicating masking, the value stored - in the Local Header will be zero. - - compressed size: (4 bytes) - uncompressed size: (4 bytes) - - The size of the file compressed and uncompressed, - respectively. When a decryption header is present it will - be placed in front of the file data and the value of the - compressed file size will include the bytes of the decryption - header. If bit 3 of the general purpose bit flag is set, - these fields are set to zero in the local header and the - correct values are put in the data descriptor and - in the central directory. If an archive is in ZIP64 format - and the value in this field is 0xFFFFFFFF, the size will be - in the corresponding 8 byte ZIP64 extended information - extra field. When encrypting the central directory, if the - local header is not in ZIP64 format and general purpose bit - flag 13 is set indicating masking, the value stored for the - uncompressed size in the Local Header will be zero. - - file name length: (2 bytes) - extra field length: (2 bytes) - file comment length: (2 bytes) - - The length of the file name, extra field, and comment - fields respectively. The combined length of any - directory record and these three fields should not - generally exceed 65,535 bytes. If input came from standard - input, the file name length is set to zero. - - disk number start: (2 bytes) - - The number of the disk on which this file begins. If an - archive is in ZIP64 format and the value in this field is - 0xFFFF, the size will be in the corresponding 4 byte zip64 - extended information extra field. - - internal file attributes: (2 bytes) - - Bits 1 and 2 are reserved for use by PKWARE. - - The lowest bit of this field indicates, if set, that - the file is apparently an ASCII or text file. If not - set, that the file apparently contains binary data. - The remaining bits are unused in version 1.0. - - The 0x0002 bit of this field indicates, if set, that a - 4 byte variable record length control field precedes each - logical record indicating the length of the record. The - record length control field is stored in little-endian byte - order. This flag is independent of text control characters, - and if used in conjunction with text data, includes any - control characters in the total length of the record. This - value is provided for mainframe data transfer support. - - external file attributes: (4 bytes) - - The mapping of the external attributes is - host-system dependent (see 'version made by'). For - MS-DOS, the low order byte is the MS-DOS directory - attribute byte. If input came from standard input, this - field is set to zero. - - relative offset of local header: (4 bytes) - - This is the offset from the start of the first disk on - which this file appears, to where the local header should - be found. If an archive is in ZIP64 format and the value - in this field is 0xFFFFFFFF, the size will be in the - corresponding 8 byte zip64 extended information extra field. - - file name: (Variable) - - The name of the file, with optional relative path. - The path stored should not contain a drive or - device letter, or a leading slash. All slashes - should be forward slashes '/' as opposed to - backwards slashes '\' for compatibility with Amiga - and UNIX file systems etc. If input came from standard - input, there is no file name field. If encrypting - the central directory and general purpose bit flag 13 is set - indicating masking, the file name stored in the Local Header - will not be the actual file name. A masking value consisting - of a unique hexadecimal value will be stored. This value will - be sequentially incremented for each file in the archive. See - the section on the Strong Encryption Specification for details - on retrieving the encrypted file name. - - extra field: (Variable) - - This is for expansion. If additional information - needs to be stored for special needs or for specific - platforms, it should be stored here. Earlier versions - of the software can then safely skip this file, and - find the next file or header. This field will be 0 - length in version 1.0. - - In order to allow different programs and different types - of information to be stored in the 'extra' field in .ZIP - files, the following structure should be used for all - programs storing data in this field: - - header1+data1 + header2+data2 . . . - - Each header should consist of: - - Header ID - 2 bytes - Data Size - 2 bytes - - Note: all fields stored in Intel low-byte/high-byte order. - - The Header ID field indicates the type of data that is in - the following data block. - - Header ID's of 0 thru 31 are reserved for use by PKWARE. - The remaining ID's can be used by third party vendors for - proprietary usage. - - The current Header ID mappings defined by PKWARE are: - - 0x0001 Zip64 extended information extra field - 0x0007 AV Info - 0x0008 Reserved for extended language encoding data (PFS) - (see APPENDIX D) - 0x0009 OS/2 - 0x000a NTFS - 0x000c OpenVMS - 0x000d UNIX - 0x000e Reserved for file stream and fork descriptors - 0x000f Patch Descriptor - 0x0014 PKCS#7 Store for X.509 Certificates - 0x0015 X.509 Certificate ID and Signature for - individual file - 0x0016 X.509 Certificate ID for Central Directory - 0x0017 Strong Encryption Header - 0x0018 Record Management Controls - 0x0019 PKCS#7 Encryption Recipient Certificate List - 0x0065 IBM S/390 (Z390), AS/400 (I400) attributes - - uncompressed - 0x0066 Reserved for IBM S/390 (Z390), AS/400 (I400) - attributes - compressed - 0x4690 POSZIP 4690 (reserved) - - Third party mappings commonly used are: - - - 0x07c8 Macintosh - 0x2605 ZipIt Macintosh - 0x2705 ZipIt Macintosh 1.3.5+ - 0x2805 ZipIt Macintosh 1.3.5+ - 0x334d Info-ZIP Macintosh - 0x4341 Acorn/SparkFS - 0x4453 Windows NT security descriptor (binary ACL) - 0x4704 VM/CMS - 0x470f MVS - 0x4b46 FWKCS MD5 (see below) - 0x4c41 OS/2 access control list (text ACL) - 0x4d49 Info-ZIP OpenVMS - 0x4f4c Xceed original location extra field - 0x5356 AOS/VS (ACL) - 0x5455 extended timestamp - 0x554e Xceed unicode extra field - 0x5855 Info-ZIP UNIX (original, also OS/2, NT, etc) - 0x6375 Info-ZIP Unicode Comment Extra Field - 0x6542 BeOS/BeBox - 0x7075 Info-ZIP Unicode Path Extra Field - 0x756e ASi UNIX - 0x7855 Info-ZIP UNIX (new) - 0xa220 Microsoft Open Packaging Growth Hint - 0xfd4a SMS/QDOS - - Detailed descriptions of Extra Fields defined by third - party mappings will be documented as information on - these data structures is made available to PKWARE. - PKWARE does not guarantee the accuracy of any published - third party data. - - The Data Size field indicates the size of the following - data block. Programs can use this value to skip to the - next header block, passing over any data blocks that are - not of interest. - - Note: As stated above, the size of the entire .ZIP file - header, including the file name, comment, and extra - field should not exceed 64K in size. - - In case two different programs should appropriate the same - Header ID value, it is strongly recommended that each - program place a unique signature of at least two bytes in - size (and preferably 4 bytes or bigger) at the start of - each data area. Every program should verify that its - unique signature is present, in addition to the Header ID - value being correct, before assuming that it is a block of - known type. - - -Zip64 Extended Information Extra Field (0x0001): - - The following is the layout of the zip64 extended - information "extra" block. If one of the size or - offset fields in the Local or Central directory - record is too small to hold the required data, - a Zip64 extended information record is created. - The order of the fields in the zip64 extended - information record is fixed, but the fields will - only appear if the corresponding Local or Central - directory record field is set to 0xFFFF or 0xFFFFFFFF. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (ZIP64) 0x0001 2 bytes Tag for this "extra" block type - Size 2 bytes Size of this "extra" block - Original - Size 8 bytes Original uncompressed file size - Compressed - Size 8 bytes Size of compressed data - Relative Header - Offset 8 bytes Offset of local header record - Disk Start - Number 4 bytes Number of the disk on which - this file starts - - This entry in the Local header must include BOTH original - and compressed file size fields. If encrypting the - central directory and bit 13 of the general purpose bit - flag is set indicating masking, the value stored in the - Local Header for the original file size will be zero. - - - -OS/2 Extra Field (0x0009): - - The following is the layout of the OS/2 attributes "extra" - block. (Last Revision 09/05/95) - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (OS/2) 0x0009 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - BSize 4 bytes Uncompressed Block Size - CType 2 bytes Compression type - EACRC 4 bytes CRC value for uncompress block - (var) variable Compressed block - - The OS/2 extended attribute structure (FEA2LIST) is - compressed and then stored in it's entirety within this - structure. There will only ever be one "block" of data in - VarFields[]. - - -NTFS Extra Field (0x000a): - - The following is the layout of the NTFS attributes - "extra" block. (Note: At this time the Mtime, Atime - and Ctime values may be used on any WIN32 system.) - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (NTFS) 0x000a 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the total "extra" block - Reserved 4 bytes Reserved for future use - Tag1 2 bytes NTFS attribute tag value #1 - Size1 2 bytes Size of attribute #1, in bytes - (var.) Size1 Attribute #1 data - . - . - . - TagN 2 bytes NTFS attribute tag value #N - SizeN 2 bytes Size of attribute #N, in bytes - (var.) SizeN Attribute #N data - - For NTFS, values for Tag1 through TagN are as follows: - (currently only one set of attributes is defined for NTFS) - - Tag Size Description - ----- ---- ----------- - 0x0001 2 bytes Tag for attribute #1 - Size1 2 bytes Size of attribute #1, in bytes - Mtime 8 bytes File last modification time - Atime 8 bytes File last access time - Ctime 8 bytes File creation time - - -OpenVMS Extra Field (0x000c): - - The following is the layout of the OpenVMS attributes - "extra" block. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (VMS) 0x000c 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the total "extra" block - CRC 4 bytes 32-bit CRC for remainder of the block - Tag1 2 bytes OpenVMS attribute tag value #1 - Size1 2 bytes Size of attribute #1, in bytes - (var.) Size1 Attribute #1 data - . - . - . - TagN 2 bytes OpenVMS attribute tag value #N - SizeN 2 bytes Size of attribute #N, in bytes - (var.) SizeN Attribute #N data - - Rules: - - 1. There will be one or more of attributes present, which - will each be preceded by the above TagX & SizeX values. - These values are identical to the ATR$C_XXXX and - ATR$S_XXXX constants which are defined in ATR.H under - OpenVMS C. Neither of these values will ever be zero. - - 2. No word alignment or padding is performed. - - 3. A well-behaved PKZIP/OpenVMS program should never produce - more than one sub-block with the same TagX value. Also, - there will never be more than one "extra" block of type - 0x000c in a particular directory record. - - -UNIX Extra Field (0x000d): - - The following is the layout of the UNIX "extra" block. - Note: all fields are stored in Intel low-byte/high-byte - order. - - Value Size Description - ----- ---- ----------- - (UNIX) 0x000d 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - Atime 4 bytes File last access time - Mtime 4 bytes File last modification time - Uid 2 bytes File user ID - Gid 2 bytes File group ID - (var) variable Variable length data field - - The variable length data field will contain file type - specific data. Currently the only values allowed are - the original "linked to" file names for hard or symbolic - links, and the major and minor device node numbers for - character and block device nodes. Since device nodes - cannot be either symbolic or hard links, only one set of - variable length data is stored. Link files will have the - name of the original file stored. This name is NOT NULL - terminated. Its size can be determined by checking TSize - - 12. Device entries will have eight bytes stored as two 4 - byte entries (in little endian format). The first entry - will be the major device number, and the second the minor - device number. - - -PATCH Descriptor Extra Field (0x000f): - - The following is the layout of the Patch Descriptor "extra" - block. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (Patch) 0x000f 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the total "extra" block - Version 2 bytes Version of the descriptor - Flags 4 bytes Actions and reactions (see below) - OldSize 4 bytes Size of the file about to be patched - OldCRC 4 bytes 32-bit CRC of the file to be patched - NewSize 4 bytes Size of the resulting file - NewCRC 4 bytes 32-bit CRC of the resulting file - - Actions and reactions - - Bits Description - ---- ---------------- - 0 Use for auto detection - 1 Treat as a self-patch - 2-3 RESERVED - 4-5 Action (see below) - 6-7 RESERVED - 8-9 Reaction (see below) to absent file - 10-11 Reaction (see below) to newer file - 12-13 Reaction (see below) to unknown file - 14-15 RESERVED - 16-31 RESERVED - - Actions - - Action Value - ------ ----- - none 0 - add 1 - delete 2 - patch 3 - - Reactions - - Reaction Value - -------- ----- - ask 0 - skip 1 - ignore 2 - fail 3 - - Patch support is provided by PKPatchMaker(tm) technology and is - covered under U.S. Patents and Patents Pending. The use or - implementation in a product of certain technological aspects set - forth in the current APPNOTE, including those with regard to - strong encryption, patching, or extended tape operations requires - a license from PKWARE. Please contact PKWARE with regard to - acquiring a license. - - -PKCS#7 Store for X.509 Certificates (0x0014): - - This field contains information about each of the certificates - files may be signed with. When the Central Directory Encryption - feature is enabled for a ZIP file, this record will appear in - the Archive Extra Data Record, otherwise it will appear in the - first central directory record and will be ignored in any - other record. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (Store) 0x0014 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the store data - TData TSize Data about the store - - - -X.509 Certificate ID and Signature for individual file (0x0015): - - This field contains the information about which certificate in - the PKCS#7 store was used to sign a particular file. It also - contains the signature data. This field can appear multiple - times, but can only appear once per certificate. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (CID) 0x0015 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of data that follows - TData TSize Signature Data - - -X.509 Certificate ID and Signature for central directory (0x0016): - - This field contains the information about which certificate in - the PKCS#7 store was used to sign the central directory structure. - When the Central Directory Encryption feature is enabled for a - ZIP file, this record will appear in the Archive Extra Data Record, - otherwise it will appear in the first central directory record. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (CDID) 0x0016 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of data that follows - TData TSize Data - - -Strong Encryption Header (0x0017): - - Value Size Description - ----- ---- ----------- - 0x0017 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of data that follows - Format 2 bytes Format definition for this record - AlgID 2 bytes Encryption algorithm identifier - Bitlen 2 bytes Bit length of encryption key - Flags 2 bytes Processing flags - CertData TSize-8 Certificate decryption extra field data - (refer to the explanation for CertData - in the section describing the - Certificate Processing Method under - the Strong Encryption Specification) - - - -Record Management Controls (0x0018): - - Value Size Description - ----- ---- ----------- -(Rec-CTL) 0x0018 2 bytes Tag for this "extra" block type - CSize 2 bytes Size of total extra block data - Tag1 2 bytes Record control attribute 1 - Size1 2 bytes Size of attribute 1, in bytes - Data1 Size1 Attribute 1 data - . - . - . - TagN 2 bytes Record control attribute N - SizeN 2 bytes Size of attribute N, in bytes - DataN SizeN Attribute N data - - - -PKCS#7 Encryption Recipient Certificate List (0x0019): - - This field contains information about each of the certificates - used in encryption processing and it can be used to identify who is - allowed to decrypt encrypted files. This field should only appear - in the archive extra data record. This field is not required and - serves only to aide archive modifications by preserving public - encryption key data. Individual security requirements may dictate - that this data be omitted to deter information exposure. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (CStore) 0x0019 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the store data - TData TSize Data about the store - - TData: - - Value Size Description - ----- ---- ----------- - Version 2 bytes Format version number - must 0x0001 at this time - CStore (var) PKCS#7 data blob - - - -MVS Extra Field (0x0065): - - The following is the layout of the MVS "extra" block. - Note: Some fields are stored in Big Endian format. - All text is in EBCDIC format unless otherwise specified. - - Value Size Description - ----- ---- ----------- - (MVS) 0x0065 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - ID 4 bytes EBCDIC "Z390" 0xE9F3F9F0 or - "T4MV" for TargetFour - (var) TSize-4 Attribute data (see APPENDIX B) - - - -OS/400 Extra Field (0x0065): - - The following is the layout of the OS/400 "extra" block. - Note: Some fields are stored in Big Endian format. - All text is in EBCDIC format unless otherwise specified. - - Value Size Description - ----- ---- ----------- - (OS400) 0x0065 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - ID 4 bytes EBCDIC "I400" 0xC9F4F0F0 or - "T4MV" for TargetFour - (var) TSize-4 Attribute data (see APPENDIX A) - - - Third-party Mappings: - - -ZipIt Macintosh Extra Field (long) (0x2605): - - The following is the layout of the ZipIt extra block - for Macintosh. The local-header and central-header versions - are identical. This block must be present if the file is - stored MacBinary-encoded and it should not be used if the file - is not stored MacBinary-encoded. - - Value Size Description - ----- ---- ----------- - (Mac2) 0x2605 Short tag for this extra block type - TSize Short total data size for this block - "ZPIT" beLong extra-field signature - FnLen Byte length of FileName - FileName variable full Macintosh filename - FileType Byte[4] four-byte Mac file type string - Creator Byte[4] four-byte Mac creator string - - - -ZipIt Macintosh Extra Field (short, for files) (0x2705): - - The following is the layout of a shortened variant of the - ZipIt extra block for Macintosh (without "full name" entry). - This variant is used by ZipIt 1.3.5 and newer for entries of - files (not directories) that do not have a MacBinary encoded - file. The local-header and central-header versions are identical. - - Value Size Description - ----- ---- ----------- - (Mac2b) 0x2705 Short tag for this extra block type - TSize Short total data size for this block (12) - "ZPIT" beLong extra-field signature - FileType Byte[4] four-byte Mac file type string - Creator Byte[4] four-byte Mac creator string - fdFlags beShort attributes from FInfo.frFlags, - may be omitted - 0x0000 beShort reserved, may be omitted - - - -ZipIt Macintosh Extra Field (short, for directories) (0x2805): - - The following is the layout of a shortened variant of the - ZipIt extra block for Macintosh used only for directory - entries. This variant is used by ZipIt 1.3.5 and newer to - save some optional Mac-specific information about directories. - The local-header and central-header versions are identical. - - Value Size Description - ----- ---- ----------- - (Mac2c) 0x2805 Short tag for this extra block type - TSize Short total data size for this block (12) - "ZPIT" beLong extra-field signature - frFlags beShort attributes from DInfo.frFlags, may - be omitted - View beShort ZipIt view flag, may be omitted - - - The View field specifies ZipIt-internal settings as follows: - - Bits of the Flags: - bit 0 if set, the folder is shown expanded (open) - when the archive contents are viewed in ZipIt. - bits 1-15 reserved, zero; - - - -FWKCS MD5 Extra Field (0x4b46): - - The FWKCS Contents_Signature System, used in - automatically identifying files independent of file name, - optionally adds and uses an extra field to support the - rapid creation of an enhanced contents_signature: - - Header ID = 0x4b46 - Data Size = 0x0013 - Preface = 'M','D','5' - followed by 16 bytes containing the uncompressed file's - 128_bit MD5 hash(1), low byte first. - - When FWKCS revises a .ZIP file central directory to add - this extra field for a file, it also replaces the - central directory entry for that file's uncompressed - file length with a measured value. - - FWKCS provides an option to strip this extra field, if - present, from a .ZIP file central directory. In adding - this extra field, FWKCS preserves .ZIP file Authenticity - Verification; if stripping this extra field, FWKCS - preserves all versions of AV through PKZIP version 2.04g. - - FWKCS, and FWKCS Contents_Signature System, are - trademarks of Frederick W. Kantor. - - (1) R. Rivest, RFC1321.TXT, MIT Laboratory for Computer - Science and RSA Data Security, Inc., April 1992. - ll.76-77: "The MD5 algorithm is being placed in the - public domain for review and possible adoption as a - standard." - - - -Info-ZIP Unicode Comment Extra Field (0x6375): - - Stores the UTF-8 version of the file comment as stored in the - central directory header. (Last Revision 20070912) - - Value Size Description - ----- ---- ----------- - (UCom) 0x6375 Short tag for this extra block type ("uc") - TSize Short total data size for this block - Version 1 byte version of this extra field, currently 1 - ComCRC32 4 bytes Comment Field CRC32 Checksum - UnicodeCom Variable UTF-8 version of the entry comment - - Currently Version is set to the number 1. If there is a need - to change this field, the version will be incremented. Changes - may not be backward compatible so this extra field should not be - used if the version is not recognized. - - The ComCRC32 is the standard zip CRC32 checksum of the File Comment - field in the central directory header. This is used to verify that - the comment field has not changed since the Unicode Comment extra field - was created. This can happen if a utility changes the File Comment - field but does not update the UTF-8 Comment extra field. If the CRC - check fails, this Unicode Comment extra field should be ignored and - the File Comment field in the header should be used instead. - - The UnicodeCom field is the UTF-8 version of the File Comment field - in the header. As UnicodeCom is defined to be UTF-8, no UTF-8 byte - order mark (BOM) is used. The length of this field is determined by - subtracting the size of the previous fields from TSize. If both the - File Name and Comment fields are UTF-8, the new General Purpose Bit - Flag, bit 11 (Language encoding flag (EFS)), can be used to indicate - both the header File Name and Comment fields are UTF-8 and, in this - case, the Unicode Path and Unicode Comment extra fields are not - needed and should not be created. Note that, for backward - compatibility, bit 11 should only be used if the native character set - of the paths and comments being zipped up are already in UTF-8. It is - expected that the same file comment storage method, either general - purpose bit 11 or extra fields, be used in both the Local and Central - Directory Header for a file. - - - -Info-ZIP Unicode Path Extra Field (0x7075): - - Stores the UTF-8 version of the file name field as stored in the - local header and central directory header. (Last Revision 20070912) - - Value Size Description - ----- ---- ----------- - (UPath) 0x7075 Short tag for this extra block type ("up") - TSize Short total data size for this block - Version 1 byte version of this extra field, currently 1 - NameCRC32 4 bytes File Name Field CRC32 Checksum - UnicodeName Variable UTF-8 version of the entry File Name - - Currently Version is set to the number 1. If there is a need - to change this field, the version will be incremented. Changes - may not be backward compatible so this extra field should not be - used if the version is not recognized. - - The NameCRC32 is the standard zip CRC32 checksum of the File Name - field in the header. This is used to verify that the header - File Name field has not changed since the Unicode Path extra field - was created. This can happen if a utility renames the File Name but - does not update the UTF-8 path extra field. If the CRC check fails, - this UTF-8 Path Extra Field should be ignored and the File Name field - in the header should be used instead. - - The UnicodeName is the UTF-8 version of the contents of the File Name - field in the header. As UnicodeName is defined to be UTF-8, no UTF-8 - byte order mark (BOM) is used. The length of this field is determined - by subtracting the size of the previous fields from TSize. If both - the File Name and Comment fields are UTF-8, the new General Purpose - Bit Flag, bit 11 (Language encoding flag (EFS)), can be used to - indicate that both the header File Name and Comment fields are UTF-8 - and, in this case, the Unicode Path and Unicode Comment extra fields - are not needed and should not be created. Note that, for backward - compatibility, bit 11 should only be used if the native character set - of the paths and comments being zipped up are already in UTF-8. It is - expected that the same file name storage method, either general - purpose bit 11 or extra fields, be used in both the Local and Central - Directory Header for a file. - - - -Microsoft Open Packaging Growth Hint (0xa220): - - Value Size Description - ----- ---- ----------- - 0xa220 Short tag for this extra block type - TSize Short size of Sig + PadVal + Padding - Sig Short verification signature (A028) - PadVal Short Initial padding value - Padding variable filled with NULL characters - - - file comment: (Variable) - - The comment for this file. - - number of this disk: (2 bytes) - - The number of this disk, which contains central - directory end record. If an archive is in ZIP64 format - and the value in this field is 0xFFFF, the size will - be in the corresponding 4 byte zip64 end of central - directory field. - - - number of the disk with the start of the central - directory: (2 bytes) - - The number of the disk on which the central - directory starts. If an archive is in ZIP64 format - and the value in this field is 0xFFFF, the size will - be in the corresponding 4 byte zip64 end of central - directory field. - - total number of entries in the central dir on - this disk: (2 bytes) - - The number of central directory entries on this disk. - If an archive is in ZIP64 format and the value in - this field is 0xFFFF, the size will be in the - corresponding 8 byte zip64 end of central - directory field. - - total number of entries in the central dir: (2 bytes) - - The total number of files in the .ZIP file. If an - archive is in ZIP64 format and the value in this field - is 0xFFFF, the size will be in the corresponding 8 byte - zip64 end of central directory field. - - size of the central directory: (4 bytes) - - The size (in bytes) of the entire central directory. - If an archive is in ZIP64 format and the value in - this field is 0xFFFFFFFF, the size will be in the - corresponding 8 byte zip64 end of central - directory field. - - offset of start of central directory with respect to - the starting disk number: (4 bytes) - - Offset of the start of the central directory on the - disk on which the central directory starts. If an - archive is in ZIP64 format and the value in this - field is 0xFFFFFFFF, the size will be in the - corresponding 8 byte zip64 end of central - directory field. - - .ZIP file comment length: (2 bytes) - - The length of the comment for this .ZIP file. - - .ZIP file comment: (Variable) - - The comment for this .ZIP file. ZIP file comment data - is stored unsecured. No encryption or data authentication - is applied to this area at this time. Confidential information - should not be stored in this section. - - zip64 extensible data sector (variable size) - - (currently reserved for use by PKWARE) - - - K. Splitting and Spanning ZIP files - - Spanning is the process of segmenting a ZIP file across - multiple removable media. This support has typically only - been provided for DOS formatted floppy diskettes. - - File splitting is a newer derivative of spanning. - Splitting follows the same segmentation process as - spanning, however, it does not require writing each - segment to a unique removable medium and instead supports - placing all pieces onto local or non-removable locations - such as file systems, local drives, folders, etc... - - A key difference between spanned and split ZIP files is - that all pieces of a spanned ZIP file have the same name. - Since each piece is written to a separate volume, no name - collisions occur and each segment can reuse the original - .ZIP file name given to the archive. - - Sequence ordering for DOS spanned archives uses the DOS - volume label to determine segment numbers. Volume labels - for each segment are written using the form PKBACK#xxx, - where xxx is the segment number written as a decimal - value from 001 - nnn. - - Split ZIP files are typically written to the same location - and are subject to name collisions if the spanned name - format is used since each segment will reside on the same - drive. To avoid name collisions, split archives are named - as follows. - - Segment 1 = filename.z01 - Segment n-1 = filename.z(n-1) - Segment n = filename.zip - - The .ZIP extension is used on the last segment to support - quickly reading the central directory. The segment number - n should be a decimal value. - - Spanned ZIP files may be PKSFX Self-extracting ZIP files. - PKSFX files may also be split, however, in this case - the first segment must be named filename.exe. The first - segment of a split PKSFX archive must be large enough to - include the entire executable program. - - Capacities for split archives are as follows. - - Maximum number of segments = 4,294,967,295 - 1 - Maximum .ZIP segment size = 4,294,967,295 bytes - Minimum segment size = 64K - Maximum PKSFX segment size = 2,147,483,647 bytes - - Segment sizes may be different however by convention, all - segment sizes should be the same with the exception of the - last, which may be smaller. Local and central directory - header records must never be split across a segment boundary. - When writing a header record, if the number of bytes remaining - within a segment is less than the size of the header record, - end the current segment and write the header at the start - of the next segment. The central directory may span segment - boundaries, but no single record in the central directory - should be split across segments. - - Spanned/Split archives created using PKZIP for Windows - (V2.50 or greater), PKZIP Command Line (V2.50 or greater), - or PKZIP Explorer will include a special spanning - signature as the first 4 bytes of the first segment of - the archive. This signature (0x08074b50) will be - followed immediately by the local header signature for - the first file in the archive. - - A special spanning marker may also appear in spanned/split - archives if the spanning or splitting process starts but - only requires one segment. In this case the 0x08074b50 - signature will be replaced with the temporary spanning - marker signature of 0x30304b50. Split archives can - only be uncompressed by other versions of PKZIP that - know how to create a split archive. - - The signature value 0x08074b50 is also used by some - ZIP implementations as a marker for the Data Descriptor - record. Conflict in this alternate assignment can be - avoided by ensuring the position of the signature - within the ZIP file to determine the use for which it - is intended. - - L. General notes: - - 1) All fields unless otherwise noted are unsigned and stored - in Intel low-byte:high-byte, low-word:high-word order. - - 2) String fields are not null terminated, since the - length is given explicitly. - - 3) The entries in the central directory may not necessarily - be in the same order that files appear in the .ZIP file. - - 4) If one of the fields in the end of central directory - record is too small to hold required data, the field - should be set to -1 (0xFFFF or 0xFFFFFFFF) and the - ZIP64 format record should be created. - - 5) The end of central directory record and the - Zip64 end of central directory locator record must - reside on the same disk when splitting or spanning - an archive. - -VI. Explanation of compression methods --------------------------------------- - -UnShrinking - Method 1 ----------------------- - -Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm -with partial clearing. The initial code size is 9 bits, and -the maximum code size is 13 bits. Shrinking differs from -conventional Dynamic Ziv-Lempel-Welch implementations in several -respects: - -1) The code size is controlled by the compressor, and is not - automatically increased when codes larger than the current - code size are created (but not necessarily used). When - the decompressor encounters the code sequence 256 - (decimal) followed by 1, it should increase the code size - read from the input stream to the next bit size. No - blocking of the codes is performed, so the next code at - the increased size should be read from the input stream - immediately after where the previous code at the smaller - bit size was read. Again, the decompressor should not - increase the code size used until the sequence 256,1 is - encountered. - -2) When the table becomes full, total clearing is not - performed. Rather, when the compressor emits the code - sequence 256,2 (decimal), the decompressor should clear - all leaf nodes from the Ziv-Lempel tree, and continue to - use the current code size. The nodes that are cleared - from the Ziv-Lempel tree are then re-used, with the lowest - code value re-used first, and the highest code value - re-used last. The compressor can emit the sequence 256,2 - at any time. - -Expanding - Methods 2-5 ------------------------ - -The Reducing algorithm is actually a combination of two -distinct algorithms. The first algorithm compresses repeated -byte sequences, and the second algorithm takes the compressed -stream from the first algorithm and applies a probabilistic -compression method. - -The probabilistic compression stores an array of 'follower -sets' S(j), for j=0 to 255, corresponding to each possible -ASCII character. Each set contains between 0 and 32 -characters, to be denoted as S(j)[0],...,S(j)[m], where m<32. -The sets are stored at the beginning of the data area for a -Reduced file, in reverse order, with S(255) first, and S(0) -last. - -The sets are encoded as { N(j), S(j)[0],...,S(j)[N(j)-1] }, -where N(j) is the size of set S(j). N(j) can be 0, in which -case the follower set for S(j) is empty. Each N(j) value is -encoded in 6 bits, followed by N(j) eight bit character values -corresponding to S(j)[0] to S(j)[N(j)-1] respectively. If -N(j) is 0, then no values for S(j) are stored, and the value -for N(j-1) immediately follows. - -Immediately after the follower sets, is the compressed data -stream. The compressed data stream can be interpreted for the -probabilistic decompression as follows: - -let Last-Character <- 0. -loop until done - if the follower set S(Last-Character) is empty then - read 8 bits from the input stream, and copy this - value to the output stream. - otherwise if the follower set S(Last-Character) is non-empty then - read 1 bit from the input stream. - if this bit is not zero then - read 8 bits from the input stream, and copy this - value to the output stream. - otherwise if this bit is zero then - read B(N(Last-Character)) bits from the input - stream, and assign this value to I. - Copy the value of S(Last-Character)[I] to the - output stream. - - assign the last value placed on the output stream to - Last-Character. -end loop - -B(N(j)) is defined as the minimal number of bits required to -encode the value N(j)-1. - -The decompressed stream from above can then be expanded to -re-create the original file as follows: - -let State <- 0. - -loop until done - read 8 bits from the input stream into C. - case State of - 0: if C is not equal to DLE (144 decimal) then - copy C to the output stream. - otherwise if C is equal to DLE then - let State <- 1. - - 1: if C is non-zero then - let V <- C. - let Len <- L(V) - let State <- F(Len). - otherwise if C is zero then - copy the value 144 (decimal) to the output stream. - let State <- 0 - - 2: let Len <- Len + C - let State <- 3. - - 3: move backwards D(V,C) bytes in the output stream - (if this position is before the start of the output - stream, then assume that all the data before the - start of the output stream is filled with zeros). - copy Len+3 bytes from this position to the output stream. - let State <- 0. - end case -end loop - -The functions F,L, and D are dependent on the 'compression -factor', 1 through 4, and are defined as follows: - -For compression factor 1: - L(X) equals the lower 7 bits of X. - F(X) equals 2 if X equals 127 otherwise F(X) equals 3. - D(X,Y) equals the (upper 1 bit of X) * 256 + Y + 1. -For compression factor 2: - L(X) equals the lower 6 bits of X. - F(X) equals 2 if X equals 63 otherwise F(X) equals 3. - D(X,Y) equals the (upper 2 bits of X) * 256 + Y + 1. -For compression factor 3: - L(X) equals the lower 5 bits of X. - F(X) equals 2 if X equals 31 otherwise F(X) equals 3. - D(X,Y) equals the (upper 3 bits of X) * 256 + Y + 1. -For compression factor 4: - L(X) equals the lower 4 bits of X. - F(X) equals 2 if X equals 15 otherwise F(X) equals 3. - D(X,Y) equals the (upper 4 bits of X) * 256 + Y + 1. - -Imploding - Method 6 --------------------- - -The Imploding algorithm is actually a combination of two distinct -algorithms. The first algorithm compresses repeated byte -sequences using a sliding dictionary. The second algorithm is -used to compress the encoding of the sliding dictionary output, -using multiple Shannon-Fano trees. - -The Imploding algorithm can use a 4K or 8K sliding dictionary -size. The dictionary size used can be determined by bit 1 in the -general purpose flag word; a 0 bit indicates a 4K dictionary -while a 1 bit indicates an 8K dictionary. - -The Shannon-Fano trees are stored at the start of the compressed -file. The number of trees stored is defined by bit 2 in the -general purpose flag word; a 0 bit indicates two trees stored, a -1 bit indicates three trees are stored. If 3 trees are stored, -the first Shannon-Fano tree represents the encoding of the -Literal characters, the second tree represents the encoding of -the Length information, the third represents the encoding of the -Distance information. When 2 Shannon-Fano trees are stored, the -Length tree is stored first, followed by the Distance tree. - -The Literal Shannon-Fano tree, if present is used to represent -the entire ASCII character set, and contains 256 values. This -tree is used to compress any data not compressed by the sliding -dictionary algorithm. When this tree is present, the Minimum -Match Length for the sliding dictionary is 3. If this tree is -not present, the Minimum Match Length is 2. - -The Length Shannon-Fano tree is used to compress the Length part -of the (length,distance) pairs from the sliding dictionary -output. The Length tree contains 64 values, ranging from the -Minimum Match Length, to 63 plus the Minimum Match Length. - -The Distance Shannon-Fano tree is used to compress the Distance -part of the (length,distance) pairs from the sliding dictionary -output. The Distance tree contains 64 values, ranging from 0 to -63, representing the upper 6 bits of the distance value. The -distance values themselves will be between 0 and the sliding -dictionary size, either 4K or 8K. - -The Shannon-Fano trees themselves are stored in a compressed -format. The first byte of the tree data represents the number of -bytes of data representing the (compressed) Shannon-Fano tree -minus 1. The remaining bytes represent the Shannon-Fano tree -data encoded as: - - High 4 bits: Number of values at this bit length + 1. (1 - 16) - Low 4 bits: Bit Length needed to represent value + 1. (1 - 16) - -The Shannon-Fano codes can be constructed from the bit lengths -using the following algorithm: - -1) Sort the Bit Lengths in ascending order, while retaining the - order of the original lengths stored in the file. - -2) Generate the Shannon-Fano trees: - - Code <- 0 - CodeIncrement <- 0 - LastBitLength <- 0 - i <- number of Shannon-Fano codes - 1 (either 255 or 63) - - loop while i >= 0 - Code = Code + CodeIncrement - if BitLength(i) <> LastBitLength then - LastBitLength=BitLength(i) - CodeIncrement = 1 shifted left (16 - LastBitLength) - ShannonCode(i) = Code - i <- i - 1 - end loop - -3) Reverse the order of all the bits in the above ShannonCode() - vector, so that the most significant bit becomes the least - significant bit. For example, the value 0x1234 (hex) would - become 0x2C48 (hex). - -4) Restore the order of Shannon-Fano codes as originally stored - within the file. - -Example: - - This example will show the encoding of a Shannon-Fano tree - of size 8. Notice that the actual Shannon-Fano trees used - for Imploding are either 64 or 256 entries in size. - -Example: 0x02, 0x42, 0x01, 0x13 - - The first byte indicates 3 values in this table. Decoding the - bytes: - 0x42 = 5 codes of 3 bits long - 0x01 = 1 code of 2 bits long - 0x13 = 2 codes of 4 bits long - - This would generate the original bit length array of: - (3, 3, 3, 3, 3, 2, 4, 4) - - There are 8 codes in this table for the values 0 thru 7. Using - the algorithm to obtain the Shannon-Fano codes produces: - - Reversed Order Original -Val Sorted Constructed Code Value Restored Length ---- ------ ----------------- -------- -------- ------ -0: 2 1100000000000000 11 101 3 -1: 3 1010000000000000 101 001 3 -2: 3 1000000000000000 001 110 3 -3: 3 0110000000000000 110 010 3 -4: 3 0100000000000000 010 100 3 -5: 3 0010000000000000 100 11 2 -6: 4 0001000000000000 1000 1000 4 -7: 4 0000000000000000 0000 0000 4 - -The values in the Val, Order Restored and Original Length columns -now represent the Shannon-Fano encoding tree that can be used for -decoding the Shannon-Fano encoded data. How to parse the -variable length Shannon-Fano values from the data stream is beyond -the scope of this document. (See the references listed at the end of -this document for more information.) However, traditional decoding -schemes used for Huffman variable length decoding, such as the -Greenlaw algorithm, can be successfully applied. - -The compressed data stream begins immediately after the -compressed Shannon-Fano data. The compressed data stream can be -interpreted as follows: - -loop until done - read 1 bit from input stream. - - if this bit is non-zero then (encoded data is literal data) - if Literal Shannon-Fano tree is present - read and decode character using Literal Shannon-Fano tree. - otherwise - read 8 bits from input stream. - copy character to the output stream. - otherwise (encoded data is sliding dictionary match) - if 8K dictionary size - read 7 bits for offset Distance (lower 7 bits of offset). - otherwise - read 6 bits for offset Distance (lower 6 bits of offset). - - using the Distance Shannon-Fano tree, read and decode the - upper 6 bits of the Distance value. - - using the Length Shannon-Fano tree, read and decode - the Length value. - - Length <- Length + Minimum Match Length - - if Length = 63 + Minimum Match Length - read 8 bits from the input stream, - add this value to Length. - - move backwards Distance+1 bytes in the output stream, and - copy Length characters from this position to the output - stream. (if this position is before the start of the output - stream, then assume that all the data before the start of - the output stream is filled with zeros). -end loop - -Tokenizing - Method 7 ---------------------- - -This method is not used by PKZIP. - -Deflating - Method 8 --------------------- - -The Deflate algorithm is similar to the Implode algorithm using -a sliding dictionary of up to 32K with secondary compression -from Huffman/Shannon-Fano codes. - -The compressed data is stored in blocks with a header describing -the block and the Huffman codes used in the data block. The header -format is as follows: - - Bit 0: Last Block bit This bit is set to 1 if this is the last - compressed block in the data. - Bits 1-2: Block type - 00 (0) - Block is stored - All stored data is byte aligned. - Skip bits until next byte, then next word = block - length, followed by the ones compliment of the block - length word. Remaining data in block is the stored - data. - - 01 (1) - Use fixed Huffman codes for literal and distance codes. - Lit Code Bits Dist Code Bits - --------- ---- --------- ---- - 0 - 143 8 0 - 31 5 - 144 - 255 9 - 256 - 279 7 - 280 - 287 8 - - Literal codes 286-287 and distance codes 30-31 are - never used but participate in the huffman construction. - - 10 (2) - Dynamic Huffman codes. (See expanding Huffman codes) - - 11 (3) - Reserved - Flag a "Error in compressed data" if seen. - -Expanding Huffman Codes ------------------------ -If the data block is stored with dynamic Huffman codes, the Huffman -codes are sent in the following compressed format: - - 5 Bits: # of Literal codes sent - 256 (256 - 286) - All other codes are never sent. - 5 Bits: # of Dist codes - 1 (1 - 32) - 4 Bits: # of Bit Length codes - 3 (3 - 19) - -The Huffman codes are sent as bit lengths and the codes are built as -described in the implode algorithm. The bit lengths themselves are -compressed with Huffman codes. There are 19 bit length codes: - - 0 - 15: Represent bit lengths of 0 - 15 - 16: Copy the previous bit length 3 - 6 times. - The next 2 bits indicate repeat length (0 = 3, ... ,3 = 6) - Example: Codes 8, 16 (+2 bits 11), 16 (+2 bits 10) will - expand to 12 bit lengths of 8 (1 + 6 + 5) - 17: Repeat a bit length of 0 for 3 - 10 times. (3 bits of length) - 18: Repeat a bit length of 0 for 11 - 138 times (7 bits of length) - -The lengths of the bit length codes are sent packed 3 bits per value -(0 - 7) in the following order: - - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - -The Huffman codes should be built as described in the Implode algorithm -except codes are assigned starting at the shortest bit length, i.e. the -shortest code should be all 0's rather than all 1's. Also, codes with -a bit length of zero do not participate in the tree construction. The -codes are then used to decode the bit lengths for the literal and -distance tables. - -The bit lengths for the literal tables are sent first with the number -of entries sent described by the 5 bits sent earlier. There are up -to 286 literal characters; the first 256 represent the respective 8 -bit character, code 256 represents the End-Of-Block code, the remaining -29 codes represent copy lengths of 3 thru 258. There are up to 30 -distance codes representing distances from 1 thru 32k as described -below. - - Length Codes - ------------ - Extra Extra Extra Extra - Code Bits Length Code Bits Lengths Code Bits Lengths Code Bits Length(s) - ---- ---- ------ ---- ---- ------- ---- ---- ------- ---- ---- --------- - 257 0 3 265 1 11,12 273 3 35-42 281 5 131-162 - 258 0 4 266 1 13,14 274 3 43-50 282 5 163-194 - 259 0 5 267 1 15,16 275 3 51-58 283 5 195-226 - 260 0 6 268 1 17,18 276 3 59-66 284 5 227-257 - 261 0 7 269 2 19-22 277 4 67-82 285 0 258 - 262 0 8 270 2 23-26 278 4 83-98 - 263 0 9 271 2 27-30 279 4 99-114 - 264 0 10 272 2 31-34 280 4 115-130 - - Distance Codes - -------------- - Extra Extra Extra Extra - Code Bits Dist Code Bits Dist Code Bits Distance Code Bits Distance - ---- ---- ---- ---- ---- ------ ---- ---- -------- ---- ---- -------- - 0 0 1 8 3 17-24 16 7 257-384 24 11 4097-6144 - 1 0 2 9 3 25-32 17 7 385-512 25 11 6145-8192 - 2 0 3 10 4 33-48 18 8 513-768 26 12 8193-12288 - 3 0 4 11 4 49-64 19 8 769-1024 27 12 12289-16384 - 4 1 5,6 12 5 65-96 20 9 1025-1536 28 13 16385-24576 - 5 1 7,8 13 5 97-128 21 9 1537-2048 29 13 24577-32768 - 6 2 9-12 14 6 129-192 22 10 2049-3072 - 7 2 13-16 15 6 193-256 23 10 3073-4096 - -The compressed data stream begins immediately after the -compressed header data. The compressed data stream can be -interpreted as follows: - -do - read header from input stream. - - if stored block - skip bits until byte aligned - read count and 1's compliment of count - copy count bytes data block - otherwise - loop until end of block code sent - decode literal character from input stream - if literal < 256 - copy character to the output stream - otherwise - if literal = end of block - break from loop - otherwise - decode distance from input stream - - move backwards distance bytes in the output stream, and - copy length characters from this position to the output - stream. - end loop -while not last block - -if data descriptor exists - skip bits until byte aligned - read crc and sizes -endif - -Enhanced Deflating - Method 9 ------------------------------ - -The Enhanced Deflating algorithm is similar to Deflate but -uses a sliding dictionary of up to 64K. Deflate64(tm) is supported -by the Deflate extractor. - -BZIP2 - Method 12 ------------------ - -BZIP2 is an open-source data compression algorithm developed by -Julian Seward. Information and source code for this algorithm -can be found on the internet. - -LZMA - Method 14 (EFS) ----------------------- - -LZMA is a block-oriented, general purpose data compression algorithm -developed and maintained by Igor Pavlov. It is a derivative of LZ77 -that utilizes Markov chains and a range coder. Information and -source code for this algorithm can be found on the internet. Consult -with the author of this algorithm for information on terms or -restrictions on use. - -Support for LZMA within the ZIP format is defined as follows: - -The Compression method field within the ZIP Local and Central -Header records will be set to the value 14 to indicate data was -compressed using LZMA. - -The Version needed to extract field within the ZIP Local and -Central Header records will be set to 6.3 to indicate the -minimum ZIP format version supporting this feature. - -File data compressed using the LZMA algorithm must be placed -immediately following the Local Header for the file. If a -standard ZIP encryption header is required, it will follow -the Local Header and will precede the LZMA compressed file -data segment. The location of LZMA compressed data segment -within the ZIP format will be as shown: - - [local header file 1] - [encryption header file 1] - [LZMA compressed data segment for file 1] - [data descriptor 1] - [local header file 2] - -The encryption header and data descriptor records may -be conditionally present. The LZMA Compressed Data Segment -will consist of an LZMA Properties Header followed by the -LZMA Compressed Data as shown: - - [LZMA properties header for file 1] - [LZMA compressed data for file 1] - -The LZMA Compressed Data will be stored as provided by the -LZMA compression library. Compressed size, uncompressed -size and other file characteristics about the file being -compressed must be stored in standard ZIP storage format. - -The LZMA Properties Header will store specific data required to -decompress the LZMA compressed Data. This data is set by the -LZMA compression engine using the function WriteCoderProperties() -as documented within the LZMA SDK. - -Storage fields for the property information within the LZMA -Properties Header are as follows: - - LZMA Version Information 2 bytes - LZMA Properties Size 2 bytes - LZMA Properties Data variable, defined by "LZMA Properties Size" - -LZMA Version Information - this field identifies which version of - the LZMA SDK was used to compress a file. The first byte will - store the major version number of the LZMA SDK and the second - byte will store the minor number. - -LZMA Properties Size - this field defines the size of the remaining - property data. Typically this size should be determined by the - version of the SDK. This size field is included as a convenience - and to help avoid any ambiguity should it arise in the future due - to changes in this compression algorithm. - -LZMA Property Data - this variable sized field records the required - values for the decompressor as defined by the LZMA SDK. The - data stored in this field should be obtained using the - WriteCoderProperties() in the version of the SDK defined by - the "LZMA Version Information" field. - -The layout of the "LZMA Properties Data" field is a function of the -LZMA compression algorithm. It is possible that this layout may be -changed by the author over time. The data layout in version 4.32 -of the LZMA SDK defines a 5 byte array that uses 4 bytes to store -the dictionary size in little-endian order. This is preceded by a -single packed byte as the first element of the array that contains -the following fields: - - PosStateBits - LiteralPosStateBits - LiteralContextBits - -Refer to the LZMA documentation for a more detailed explanation of -these fields. - -Data compressed with method 14, LZMA, may include an end-of-stream -(EOS) marker ending the compressed data stream. This marker is not -required, but its use is highly recommended to facilitate processing -and implementers should include the EOS marker whenever possible. -When the EOS marker is used, general purpose bit 1 must be set. If -general purpose bit 1 is not set, the EOS marker is not present. - -WavPack - Method 97 -------------------- - -Information describing the use of compression method 97 is -provided by WinZIP International, LLC. This method relies on the -open source WavPack audio compression utility developed by David Bryant. -Information on WavPack is available at www.wavpack.com. Please consult -with the author of this algorithm for information on terms and -restrictions on use. - -WavPack data for a file begins immediately after the end of the -local header data. This data is the output from WavPack compression -routines. Within the ZIP file, the use of WavPack compression is -indicated by setting the compression method field to a value of 97 -in both the local header and the central directory header. The Version -needed to extract and version made by fields use the same values as are -used for data compressed using the Deflate algorithm. - -An implementation note for storing digital sample data when using -WavPack compression within ZIP files is that all of the bytes of -the sample data should be compressed. This includes any unused -bits up to the byte boundary. An example is a 2 byte sample that -uses only 12 bits for the sample data with 4 unused bits. If only -12 bits are passed as the sample size to the WavPack routines, the 4 -unused bits will be set to 0 on extraction regardless of their original -state. To avoid this, the full 16 bits of the sample data size -should be provided. - -PPMd - Method 98 ----------------- - -PPMd is a data compression algorithm developed by Dmitry Shkarin -which includes a carryless rangecoder developed by Dmitry Subbotin. -This algorithm is based on predictive phrase matching on multiple -order contexts. Information and source code for this algorithm -can be found on the internet. Consult with the author of this -algorithm for information on terms or restrictions on use. - -Support for PPMd within the ZIP format currently is provided only -for version I, revision 1 of the algorithm. Storage requirements -for using this algorithm are as follows: - -Parameters needed to control the algorithm are stored in the two -bytes immediately preceding the compressed data. These bytes are -used to store the following fields: - -Model order - sets the maximum model order, default is 8, possible - values are from 2 to 16 inclusive - -Sub-allocator size - sets the size of sub-allocator in MB, default is 50, - possible values are from 1MB to 256MB inclusive - -Model restoration method - sets the method used to restart context - model at memory insufficiency, values are: - - 0 - restarts model from scratch - default - 1 - cut off model - decreases performance by as much as 2x - 2 - freeze context tree - not recommended - -An example for packing these fields into the 2 byte storage field is -illustrated below. These values are stored in Intel low-byte/high-byte -order. - -wPPMd = (Model order - 1) + - ((Sub-allocator size - 1) << 4) + - (Model restoration method << 12) - - -VII. Traditional PKWARE Encryption ----------------------------------- - -The following information discusses the decryption steps -required to support traditional PKWARE encryption. This -form of encryption is considered weak by today's standards -and its use is recommended only for situations with -low security needs or for compatibility with older .ZIP -applications. - -Decryption ----------- - -PKWARE is grateful to Mr. Roger Schlafly for his expert contribution -towards the development of PKWARE's traditional encryption. - -PKZIP encrypts the compressed data stream. Encrypted files must -be decrypted before they can be extracted. - -Each encrypted file has an extra 12 bytes stored at the start of -the data area defining the encryption header for that file. The -encryption header is originally set to random values, and then -itself encrypted, using three, 32-bit keys. The key values are -initialized using the supplied encryption password. After each byte -is encrypted, the keys are then updated using pseudo-random number -generation techniques in combination with the same CRC-32 algorithm -used in PKZIP and described elsewhere in this document. - -The following is the basic steps required to decrypt a file: - -1) Initialize the three 32-bit keys with the password. -2) Read and decrypt the 12-byte encryption header, further - initializing the encryption keys. -3) Read and decrypt the compressed data stream using the - encryption keys. - -Step 1 - Initializing the encryption keys ------------------------------------------ - -Key(0) <- 305419896 -Key(1) <- 591751049 -Key(2) <- 878082192 - -loop for i <- 0 to length(password)-1 - update_keys(password(i)) -end loop - -Where update_keys() is defined as: - -update_keys(char): - Key(0) <- crc32(key(0),char) - Key(1) <- Key(1) + (Key(0) & 000000ffH) - Key(1) <- Key(1) * 134775813 + 1 - Key(2) <- crc32(key(2),key(1) >> 24) -end update_keys - -Where crc32(old_crc,char) is a routine that given a CRC value and a -character, returns an updated CRC value after applying the CRC-32 -algorithm described elsewhere in this document. - -Step 2 - Decrypting the encryption header ------------------------------------------ - -The purpose of this step is to further initialize the encryption -keys, based on random data, to render a plaintext attack on the -data ineffective. - -Read the 12-byte encryption header into Buffer, in locations -Buffer(0) thru Buffer(11). - -loop for i <- 0 to 11 - C <- buffer(i) ^ decrypt_byte() - update_keys(C) - buffer(i) <- C -end loop - -Where decrypt_byte() is defined as: - -unsigned char decrypt_byte() - local unsigned short temp - temp <- Key(2) | 2 - decrypt_byte <- (temp * (temp ^ 1)) >> 8 -end decrypt_byte - -After the header is decrypted, the last 1 or 2 bytes in Buffer -should be the high-order word/byte of the CRC for the file being -decrypted, stored in Intel low-byte/high-byte order. Versions of -PKZIP prior to 2.0 used a 2 byte CRC check; a 1 byte CRC check is -used on versions after 2.0. This can be used to test if the password -supplied is correct or not. - -Step 3 - Decrypting the compressed data stream ----------------------------------------------- - -The compressed data stream can be decrypted as follows: - -loop until done - read a character into C - Temp <- C ^ decrypt_byte() - update_keys(temp) - output Temp -end loop - - -VIII. Strong Encryption Specification -------------------------------------- - -The Strong Encryption technology defined in this specification is -covered under a pending patent application. The use or implementation -in a product of certain technological aspects set forth in the current -APPNOTE, including those with regard to strong encryption, patching, -or extended tape operations requires a license from PKWARE. Portions -of this Strong Encryption technology are available for use at no charge. -Contact PKWARE for licensing terms and conditions. Refer to section II -of this APPNOTE (Contacting PKWARE) for information on how to -contact PKWARE. - -Version 5.x of this specification introduced support for strong -encryption algorithms. These algorithms can be used with either -a password or an X.509v3 digital certificate to encrypt each file. -This format specification supports either password or certificate -based encryption to meet the security needs of today, to enable -interoperability between users within both PKI and non-PKI -environments, and to ensure interoperability between different -computing platforms that are running a ZIP program. - -Password based encryption is the most common form of encryption -people are familiar with. However, inherent weaknesses with -passwords (e.g. susceptibility to dictionary/brute force attack) -as well as password management and support issues make certificate -based encryption a more secure and scalable option. Industry -efforts and support are defining and moving towards more advanced -security solutions built around X.509v3 digital certificates and -Public Key Infrastructures(PKI) because of the greater scalability, -administrative options, and more robust security over traditional -password based encryption. - -Most standard encryption algorithms are supported with this -specification. Reference implementations for many of these -algorithms are available from either commercial or open source -distributors. Readily available cryptographic toolkits make -implementation of the encryption features straight-forward. -This document is not intended to provide a treatise on data -encryption principles or theory. Its purpose is to document the -data structures required for implementing interoperable data -encryption within the .ZIP format. It is strongly recommended that -you have a good understanding of data encryption before reading -further. - -The algorithms introduced in Version 5.0 of this specification -include: - - RC2 40 bit, 64 bit, and 128 bit - RC4 40 bit, 64 bit, and 128 bit - DES - 3DES 112 bit and 168 bit - -Version 5.1 adds support for the following: - - AES 128 bit, 192 bit, and 256 bit - - -Version 6.1 introduces encryption data changes to support -interoperability with Smartcard and USB Token certificate storage -methods which do not support the OAEP strengthening standard. - -Version 6.2 introduces support for encrypting metadata by compressing -and encrypting the central directory data structure to reduce information -leakage. Information leakage can occur in legacy ZIP applications -through exposure of information about a file even though that file is -stored encrypted. The information exposed consists of file -characteristics stored within the records and fields defined by this -specification. This includes data such as a files name, its original -size, timestamp and CRC32 value. - -Version 6.3 introduces support for encrypting data using the Blowfish -and Twofish algorithms. These are symmetric block ciphers developed -by Bruce Schneier. Blowfish supports using a variable length key from -32 to 448 bits. Block size is 64 bits. Implementations should use 16 -rounds and the only mode supported within ZIP files is CBC. Twofish -supports key sizes 128, 192 and 256 bits. Block size is 128 bits. -Implementations should use 16 rounds and the only mode supported within -ZIP files is CBC. Information and source code for both Blowfish and -Twofish algorithms can be found on the internet. Consult with the author -of these algorithms for information on terms or restrictions on use. - -Central Directory Encryption provides greater protection against -information leakage by encrypting the Central Directory structure and -by masking key values that are replicated in the unencrypted Local -Header. ZIP compatible programs that cannot interpret an encrypted -Central Directory structure cannot rely on the data in the corresponding -Local Header for decompression information. - -Extra Field records that may contain information about a file that should -not be exposed should not be stored in the Local Header and should only -be written to the Central Directory where they can be encrypted. This -design currently does not support streaming. Information in the End of -Central Directory record, the Zip64 End of Central Directory Locator, -and the Zip64 End of Central Directory records are not encrypted. Access -to view data on files within a ZIP file with an encrypted Central Directory -requires the appropriate password or private key for decryption prior to -viewing any files, or any information about the files, in the archive. - -Older ZIP compatible programs not familiar with the Central Directory -Encryption feature will no longer be able to recognize the Central -Directory and may assume the ZIP file is corrupt. Programs that -attempt streaming access using Local Headers will see invalid -information for each file. Central Directory Encryption need not be -used for every ZIP file. Its use is recommended for greater security. -ZIP files not using Central Directory Encryption should operate as -in the past. - -This strong encryption feature specification is intended to provide for -scalable, cross-platform encryption needs ranging from simple password -encryption to authenticated public/private key encryption. - -Encryption provides data confidentiality and privacy. It is -recommended that you combine X.509 digital signing with encryption -to add authentication and non-repudiation. - - -Single Password Symmetric Encryption Method: -------------------------------------------- - -The Single Password Symmetric Encryption Method using strong -encryption algorithms operates similarly to the traditional -PKWARE encryption defined in this format. Additional data -structures are added to support the processing needs of the -strong algorithms. - -The Strong Encryption data structures are: - -1. General Purpose Bits - Bits 0 and 6 of the General Purpose bit -flag in both local and central header records. Both bits set -indicates strong encryption. Bit 13, when set indicates the Central -Directory is encrypted and that selected fields in the Local Header -are masked to hide their actual value. - - -2. Extra Field 0x0017 in central header only. - - Fields to consider in this record are: - - Format - the data format identifier for this record. The only - value allowed at this time is the integer value 2. - - AlgId - integer identifier of the encryption algorithm from the - following range - - 0x6601 - DES - 0x6602 - RC2 (version needed to extract < 5.2) - 0x6603 - 3DES 168 - 0x6609 - 3DES 112 - 0x660E - AES 128 - 0x660F - AES 192 - 0x6610 - AES 256 - 0x6702 - RC2 (version needed to extract >= 5.2) - 0x6720 - Blowfish - 0x6721 - Twofish - 0x6801 - RC4 - 0xFFFF - Unknown algorithm - - Bitlen - Explicit bit length of key - - 32 - 448 bits - - Flags - Processing flags needed for decryption - - 0x0001 - Password is required to decrypt - 0x0002 - Certificates only - 0x0003 - Password or certificate required to decrypt - - Values > 0x0003 reserved for certificate processing - - -3. Decryption header record preceding compressed file data. - - -Decryption Header: - - Value Size Description - ----- ---- ----------- - IVSize 2 bytes Size of initialization vector (IV) - IVData IVSize Initialization vector for this file - Size 4 bytes Size of remaining decryption header data - Format 2 bytes Format definition for this record - AlgID 2 bytes Encryption algorithm identifier - Bitlen 2 bytes Bit length of encryption key - Flags 2 bytes Processing flags - ErdSize 2 bytes Size of Encrypted Random Data - ErdData ErdSize Encrypted Random Data - Reserved1 4 bytes Reserved certificate processing data - Reserved2 (var) Reserved for certificate processing data - VSize 2 bytes Size of password validation data - VData VSize-4 Password validation data - VCRC32 4 bytes Standard ZIP CRC32 of password validation data - - IVData - The size of the IV should match the algorithm block size. - The IVData can be completely random data. If the size of - the randomly generated data does not match the block size - it should be complemented with zero's or truncated as - necessary. If IVSize is 0,then IV = CRC32 + Uncompressed - File Size (as a 64 bit little-endian, unsigned integer value). - - Format - the data format identifier for this record. The only - value allowed at this time is the integer value 3. - - AlgId - integer identifier of the encryption algorithm from the - following range - - 0x6601 - DES - 0x6602 - RC2 (version needed to extract < 5.2) - 0x6603 - 3DES 168 - 0x6609 - 3DES 112 - 0x660E - AES 128 - 0x660F - AES 192 - 0x6610 - AES 256 - 0x6702 - RC2 (version needed to extract >= 5.2) - 0x6720 - Blowfish - 0x6721 - Twofish - 0x6801 - RC4 - 0xFFFF - Unknown algorithm - - Bitlen - Explicit bit length of key - - 32 - 448 bits - - Flags - Processing flags needed for decryption - - 0x0001 - Password is required to decrypt - 0x0002 - Certificates only - 0x0003 - Password or certificate required to decrypt - - Values > 0x0003 reserved for certificate processing - - ErdData - Encrypted random data is used to store random data that - is used to generate a file session key for encrypting - each file. SHA1 is used to calculate hash data used to - derive keys. File session keys are derived from a master - session key generated from the user-supplied password. - If the Flags field in the decryption header contains - the value 0x4000, then the ErdData field must be - decrypted using 3DES. If the value 0x4000 is not set, - then the ErdData field must be decrypted using AlgId. - - - Reserved1 - Reserved for certificate processing, if value is - zero, then Reserved2 data is absent. See the explanation - under the Certificate Processing Method for details on - this data structure. - - Reserved2 - If present, the size of the Reserved2 data structure - is located by skipping the first 4 bytes of this field - and using the next 2 bytes as the remaining size. See - the explanation under the Certificate Processing Method - for details on this data structure. - - VSize - This size value will always include the 4 bytes of the - VCRC32 data and will be greater than 4 bytes. - - VData - Random data for password validation. This data is VSize - in length and VSize must be a multiple of the encryption - block size. VCRC32 is a checksum value of VData. - VData and VCRC32 are stored encrypted and start the - stream of encrypted data for a file. - - -4. Useful Tips - -Strong Encryption is always applied to a file after compression. The -block oriented algorithms all operate in Cypher Block Chaining (CBC) -mode. The block size used for AES encryption is 16. All other block -algorithms use a block size of 8. Two ID's are defined for RC2 to -account for a discrepancy found in the implementation of the RC2 -algorithm in the cryptographic library on Windows XP SP1 and all -earlier versions of Windows. It is recommended that zero length files -not be encrypted, however programs should be prepared to extract them -if they are found within a ZIP file. - -A pseudo-code representation of the encryption process is as follows: - -Password = GetUserPassword() -MasterSessionKey = DeriveKey(SHA1(Password)) -RD = CryptographicStrengthRandomData() -For Each File - IV = CryptographicStrengthRandomData() - VData = CryptographicStrengthRandomData() - VCRC32 = CRC32(VData) - FileSessionKey = DeriveKey(SHA1(IV + RD) - ErdData = Encrypt(RD,MasterSessionKey,IV) - Encrypt(VData + VCRC32 + FileData, FileSessionKey,IV) -Done - -The function names and parameter requirements will depend on -the choice of the cryptographic toolkit selected. Almost any -toolkit supporting the reference implementations for each -algorithm can be used. The RSA BSAFE(r), OpenSSL, and Microsoft -CryptoAPI libraries are all known to work well. - - -Single Password - Central Directory Encryption: ------------------------------------------------ - -Central Directory Encryption is achieved within the .ZIP format by -encrypting the Central Directory structure. This encapsulates the metadata -most often used for processing .ZIP files. Additional metadata is stored for -redundancy in the Local Header for each file. The process of concealing -metadata by encrypting the Central Directory does not protect the data within -the Local Header. To avoid information leakage from the exposed metadata -in the Local Header, the fields containing information about a file are masked. - -Local Header: - -Masking replaces the true content of the fields for a file in the Local -Header with false information. When masked, the Local Header is not -suitable for streaming access and the options for data recovery of damaged -archives is reduced. Extra Data fields that may contain confidential -data should not be stored within the Local Header. The value set into -the Version needed to extract field should be the correct value needed to -extract the file without regard to Central Directory Encryption. The fields -within the Local Header targeted for masking when the Central Directory is -encrypted are: - - Field Name Mask Value - ------------------ --------------------------- - compression method 0 - last mod file time 0 - last mod file date 0 - crc-32 0 - compressed size 0 - uncompressed size 0 - file name (variable size) Base 16 value from the - range 1 - 0xFFFFFFFFFFFFFFFF - represented as a string whose - size will be set into the - file name length field - -The Base 16 value assigned as a masked file name is simply a sequentially -incremented value for each file starting with 1 for the first file. -Modifications to a ZIP file may cause different values to be stored for -each file. For compatibility, the file name field in the Local Header -should never be left blank. As of Version 6.2 of this specification, -the Compression Method and Compressed Size fields are not yet masked. -Fields having a value of 0xFFFF or 0xFFFFFFFF for the ZIP64 format -should not be masked. - -Encrypting the Central Directory: - -Encryption of the Central Directory does not include encryption of the -Central Directory Signature data, the Zip64 End of Central Directory -record, the Zip64 End of Central Directory Locator, or the End -of Central Directory record. The ZIP file comment data is never -encrypted. - -Before encrypting the Central Directory, it may optionally be compressed. -Compression is not required, but for storage efficiency it is assumed -this structure will be compressed before encrypting. Similarly, this -specification supports compressing the Central Directory without -requiring that it also be encrypted. Early implementations of this -feature will assume the encryption method applied to files matches the -encryption applied to the Central Directory. - -Encryption of the Central Directory is done in a manner similar to -that of file encryption. The encrypted data is preceded by a -decryption header. The decryption header is known as the Archive -Decryption Header. The fields of this record are identical to -the decryption header preceding each encrypted file. The location -of the Archive Decryption Header is determined by the value in the -Start of the Central Directory field in the Zip64 End of Central -Directory record. When the Central Directory is encrypted, the -Zip64 End of Central Directory record will always be present. - -The layout of the Zip64 End of Central Directory record for all -versions starting with 6.2 of this specification will follow the -Version 2 format. The Version 2 format is as follows: - -The leading fixed size fields within the Version 1 format for this -record remain unchanged. The record signature for both Version 1 -and Version 2 will be 0x06064b50. Immediately following the last -byte of the field known as the Offset of Start of Central -Directory With Respect to the Starting Disk Number will begin the -new fields defining Version 2 of this record. - -New fields for Version 2: - -Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - Compression Method 2 bytes Method used to compress the - Central Directory - Compressed Size 8 bytes Size of the compressed data - Original Size 8 bytes Original uncompressed size - AlgId 2 bytes Encryption algorithm ID - BitLen 2 bytes Encryption key length - Flags 2 bytes Encryption flags - HashID 2 bytes Hash algorithm identifier - Hash Length 2 bytes Length of hash data - Hash Data (variable) Hash data - -The Compression Method accepts the same range of values as the -corresponding field in the Central Header. - -The Compressed Size and Original Size values will not include the -data of the Central Directory Signature which is compressed or -encrypted. - -The AlgId, BitLen, and Flags fields accept the same range of values -the corresponding fields within the 0x0017 record. - -Hash ID identifies the algorithm used to hash the Central Directory -data. This data does not have to be hashed, in which case the -values for both the HashID and Hash Length will be 0. Possible -values for HashID are: - - Value Algorithm - ------ --------- - 0x0000 none - 0x0001 CRC32 - 0x8003 MD5 - 0x8004 SHA1 - 0x8007 RIPEMD160 - 0x800C SHA256 - 0x800D SHA384 - 0x800E SHA512 - -When the Central Directory data is signed, the same hash algorithm -used to hash the Central Directory for signing should be used. -This is recommended for processing efficiency, however, it is -permissible for any of the above algorithms to be used independent -of the signing process. - -The Hash Data will contain the hash data for the Central Directory. -The length of this data will vary depending on the algorithm used. - -The Version Needed to Extract should be set to 62. - -The value for the Total Number of Entries on the Current Disk will -be 0. These records will no longer support random access when -encrypting the Central Directory. - -When the Central Directory is compressed and/or encrypted, the -End of Central Directory record will store the value 0xFFFFFFFF -as the value for the Total Number of Entries in the Central -Directory. The value stored in the Total Number of Entries in -the Central Directory on this Disk field will be 0. The actual -values will be stored in the equivalent fields of the Zip64 -End of Central Directory record. - -Decrypting and decompressing the Central Directory is accomplished -in the same manner as decrypting and decompressing a file. - -Certificate Processing Method: ------------------------------ - -The Certificate Processing Method of for ZIP file encryption -defines the following additional data fields: - -1. Certificate Flag Values - -Additional processing flags that can be present in the Flags field of both -the 0x0017 field of the central directory Extra Field and the Decryption -header record preceding compressed file data are: - - 0x0007 - reserved for future use - 0x000F - reserved for future use - 0x0100 - Indicates non-OAEP key wrapping was used. If this - this field is set, the version needed to extract must - be at least 61. This means OAEP key wrapping is not - used when generating a Master Session Key using - ErdData. - 0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the - same algorithm used for encrypting the file contents. - 0x8000 - reserved for future use - - -2. CertData - Extra Field 0x0017 record certificate data structure - -The data structure used to store certificate data within the section -of the Extra Field defined by the CertData field of the 0x0017 -record are as shown: - - Value Size Description - ----- ---- ----------- - RCount 4 bytes Number of recipients. - HashAlg 2 bytes Hash algorithm identifier - HSize 2 bytes Hash size - SRList (var) Simple list of recipients hashed public keys - - - RCount This defines the number intended recipients whose - public keys were used for encryption. This identifies - the number of elements in the SRList. - - HashAlg This defines the hash algorithm used to calculate - the public key hash of each public key used - for encryption. This field currently supports - only the following value for SHA-1 - - 0x8004 - SHA1 - - HSize This defines the size of a hashed public key. - - SRList This is a variable length list of the hashed - public keys for each intended recipient. Each - element in this list is HSize. The total size of - SRList is determined using RCount * HSize. - - -3. Reserved1 - Certificate Decryption Header Reserved1 Data: - - Value Size Description - ----- ---- ----------- - RCount 4 bytes Number of recipients. - - RCount This defines the number intended recipients whose - public keys were used for encryption. This defines - the number of elements in the REList field defined below. - - -4. Reserved2 - Certificate Decryption Header Reserved2 Data Structures: - - - Value Size Description - ----- ---- ----------- - HashAlg 2 bytes Hash algorithm identifier - HSize 2 bytes Hash size - REList (var) List of recipient data elements - - - HashAlg This defines the hash algorithm used to calculate - the public key hash of each public key used - for encryption. This field currently supports - only the following value for SHA-1 - - 0x8004 - SHA1 - - HSize This defines the size of a hashed public key - defined in REHData. - - REList This is a variable length of list of recipient data. - Each element in this list consists of a Recipient - Element data structure as follows: - - - Recipient Element (REList) Data Structure: - - Value Size Description - ----- ---- ----------- - RESize 2 bytes Size of REHData + REKData - REHData HSize Hash of recipients public key - REKData (var) Simple key blob - - - RESize This defines the size of an individual REList - element. This value is the combined size of the - REHData field + REKData field. REHData is defined by - HSize. REKData is variable and can be calculated - for each REList element using RESize and HSize. - - REHData Hashed public key for this recipient. - - REKData Simple Key Blob. The format of this data structure - is identical to that defined in the Microsoft - CryptoAPI and generated using the CryptExportKey() - function. The version of the Simple Key Blob - supported at this time is 0x02 as defined by - Microsoft. - -Certificate Processing - Central Directory Encryption: ------------------------------------------------------- - -Central Directory Encryption using Digital Certificates will -operate in a manner similar to that of Single Password Central -Directory Encryption. This record will only be present when there -is data to place into it. Currently, data is placed into this -record when digital certificates are used for either encrypting -or signing the files within a ZIP file. When only password -encryption is used with no certificate encryption or digital -signing, this record is not currently needed. When present, this -record will appear before the start of the actual Central Directory -data structure and will be located immediately after the Archive -Decryption Header if the Central Directory is encrypted. - -The Archive Extra Data record will be used to store the following -information. Additional data may be added in future versions. - -Extra Data Fields: - -0x0014 - PKCS#7 Store for X.509 Certificates -0x0016 - X.509 Certificate ID and Signature for central directory -0x0019 - PKCS#7 Encryption Recipient Certificate List - -The 0x0014 and 0x0016 Extra Data records that otherwise would be -located in the first record of the Central Directory for digital -certificate processing. When encrypting or compressing the Central -Directory, the 0x0014 and 0x0016 records must be located in the -Archive Extra Data record and they should not remain in the first -Central Directory record. The Archive Extra Data record will also -be used to store the 0x0019 data. - -When present, the size of the Archive Extra Data record will be -included in the size of the Central Directory. The data of the -Archive Extra Data record will also be compressed and encrypted -along with the Central Directory data structure. - -Certificate Processing Differences: - -The Certificate Processing Method of encryption differs from the -Single Password Symmetric Encryption Method as follows. Instead -of using a user-defined password to generate a master session key, -cryptographically random data is used. The key material is then -wrapped using standard key-wrapping techniques. This key material -is wrapped using the public key of each recipient that will need -to decrypt the file using their corresponding private key. - -This specification currently assumes digital certificates will follow -the X.509 V3 format for 1024 bit and higher RSA format digital -certificates. Implementation of this Certificate Processing Method -requires supporting logic for key access and management. This logic -is outside the scope of this specification. - -OAEP Processing with Certificate-based Encryption: - -OAEP stands for Optimal Asymmetric Encryption Padding. It is a -strengthening technique used for small encoded items such as decryption -keys. This is commonly applied in cryptographic key-wrapping techniques -and is supported by PKCS #1. Versions 5.0 and 6.0 of this specification -were designed to support OAEP key-wrapping for certificate-based -decryption keys for additional security. - -Support for private keys stored on Smartcards or Tokens introduced -a conflict with this OAEP logic. Most card and token products do -not support the additional strengthening applied to OAEP key-wrapped -data. In order to resolve this conflict, versions 6.1 and above of this -specification will no longer support OAEP when encrypting using -digital certificates. - -Versions of PKZIP available during initial development of the -certificate processing method set a value of 61 into the -version needed to extract field for a file. This indicates that -non-OAEP key wrapping is used. This affects certificate encryption -only, and password encryption functions should not be affected by -this value. This means values of 61 may be found on files encrypted -with certificates only, or on files encrypted with both password -encryption and certificate encryption. Files encrypted with both -methods can safely be decrypted using the password methods documented. - -IX. Change Process ------------------- - -In order for the .ZIP file format to remain a viable definition, this -specification should be considered as open for periodic review and -revision. Although this format was originally designed with a -certain level of extensibility, not all changes in technology -(present or future) were or will be necessarily considered in its -design. If your application requires new definitions to the -extensible sections in this format, or if you would like to -submit new data structures, please forward your request to -zipformat@pkware.com. All submissions will be reviewed by the -ZIP File Specification Committee for possible inclusion into -future versions of this specification. Periodic revisions -to this specification will be published to ensure interoperability. -We encourage comments and feedback that may help improve clarity -or content. - -X. Incorporating PKWARE Proprietary Technology into Your Product ----------------------------------------------------------------- - -PKWARE is committed to the interoperability and advancement of the -.ZIP format. PKWARE offers a free license for certain technological -aspects described above under certain restrictions and conditions. -However, the use or implementation in a product of certain technological -aspects set forth in the current APPNOTE, including those with regard to -strong encryption, patching, or extended tape operations requires a -license from PKWARE. Please contact PKWARE with regard to acquiring -a license. - -XI. Acknowledgements ---------------------- - -In addition to the above mentioned contributors to PKZIP and PKUNZIP, -I would like to extend special thanks to Robert Mahoney for suggesting -the extension .ZIP for this software. - -XII. References ---------------- - - Fiala, Edward R., and Greene, Daniel H., "Data compression with - finite windows", Communications of the ACM, Volume 32, Number 4, - April 1989, pages 490-505. - - Held, Gilbert, "Data Compression, Techniques and Applications, - Hardware and Software Considerations", John Wiley & Sons, 1987. - - Huffman, D.A., "A method for the construction of minimum-redundancy - codes", Proceedings of the IRE, Volume 40, Number 9, September 1952, - pages 1098-1101. - - Nelson, Mark, "LZW Data Compression", Dr. Dobbs Journal, Volume 14, - Number 10, October 1989, pages 29-37. - - Nelson, Mark, "The Data Compression Book", M&T Books, 1991. - - Storer, James A., "Data Compression, Methods and Theory", - Computer Science Press, 1988 - - Welch, Terry, "A Technique for High-Performance Data Compression", - IEEE Computer, Volume 17, Number 6, June 1984, pages 8-19. - - Ziv, J. and Lempel, A., "A universal algorithm for sequential data - compression", Communications of the ACM, Volume 30, Number 6, - June 1987, pages 520-540. - - Ziv, J. and Lempel, A., "Compression of individual sequences via - variable-rate coding", IEEE Transactions on Information Theory, - Volume 24, Number 5, September 1978, pages 530-536. - - -APPENDIX A - AS/400 Extra Field (0x0065) Attribute Definitions --------------------------------------------------------------- - -Field Definition Structure: - - a. field length including length 2 bytes - b. field code 2 bytes - c. data x bytes - -Field Code Description - 4001 Source type i.e. CLP etc - 4002 The text description of the library - 4003 The text description of the file - 4004 The text description of the member - 4005 x'F0' or 0 is PF-DTA, x'F1' or 1 is PF_SRC - 4007 Database Type Code 1 byte - 4008 Database file and fields definition - 4009 GZIP file type 2 bytes - 400B IFS code page 2 bytes - 400C IFS Creation Time 4 bytes - 400D IFS Access Time 4 bytes - 400E IFS Modification time 4 bytes - 005C Length of the records in the file 2 bytes - 0068 GZIP two words 8 bytes - -APPENDIX B - z/OS Extra Field (0x0065) Attribute Definitions ------------------------------------------------------------- - -Field Definition Structure: - - a. field length including length 2 bytes - b. field code 2 bytes - c. data x bytes - -Field Code Description - 0001 File Type 2 bytes - 0002 NonVSAM Record Format 1 byte - 0003 Reserved - 0004 NonVSAM Block Size 2 bytes Big Endian - 0005 Primary Space Allocation 3 bytes Big Endian - 0006 Secondary Space Allocation 3 bytes Big Endian - 0007 Space Allocation Type1 byte flag - 0008 Modification Date Retired with PKZIP 5.0 + - 0009 Expiration Date Retired with PKZIP 5.0 + - 000A PDS Directory Block Allocation 3 bytes Big Endian binary value - 000B NonVSAM Volume List variable - 000C UNIT Reference Retired with PKZIP 5.0 + - 000D DF/SMS Management Class 8 bytes EBCDIC Text Value - 000E DF/SMS Storage Class 8 bytes EBCDIC Text Value - 000F DF/SMS Data Class 8 bytes EBCDIC Text Value - 0010 PDS/PDSE Member Info. 30 bytes - 0011 VSAM sub-filetype 2 bytes - 0012 VSAM LRECL 13 bytes EBCDIC "(num_avg num_max)" - 0013 VSAM Cluster Name Retired with PKZIP 5.0 + - 0014 VSAM KSDS Key Information 13 bytes EBCDIC "(num_length num_position)" - 0015 VSAM Average LRECL 5 bytes EBCDIC num_value padded with blanks - 0016 VSAM Maximum LRECL 5 bytes EBCDIC num_value padded with blanks - 0017 VSAM KSDS Key Length 5 bytes EBCDIC num_value padded with blanks - 0018 VSAM KSDS Key Position 5 bytes EBCDIC num_value padded with blanks - 0019 VSAM Data Name 1-44 bytes EBCDIC text string - 001A VSAM KSDS Index Name 1-44 bytes EBCDIC text string - 001B VSAM Catalog Name 1-44 bytes EBCDIC text string - 001C VSAM Data Space Type 9 bytes EBCDIC text string - 001D VSAM Data Space Primary 9 bytes EBCDIC num_value left-justified - 001E VSAM Data Space Secondary 9 bytes EBCDIC num_value left-justified - 001F VSAM Data Volume List variable EBCDIC text list of 6-character Volume IDs - 0020 VSAM Data Buffer Space 8 bytes EBCDIC num_value left-justified - 0021 VSAM Data CISIZE 5 bytes EBCDIC num_value left-justified - 0022 VSAM Erase Flag 1 byte flag - 0023 VSAM Free CI % 3 bytes EBCDIC num_value left-justified - 0024 VSAM Free CA % 3 bytes EBCDIC num_value left-justified - 0025 VSAM Index Volume List variable EBCDIC text list of 6-character Volume IDs - 0026 VSAM Ordered Flag 1 byte flag - 0027 VSAM REUSE Flag 1 byte flag - 0028 VSAM SPANNED Flag 1 byte flag - 0029 VSAM Recovery Flag 1 byte flag - 002A VSAM WRITECHK Flag 1 byte flag - 002B VSAM Cluster/Data SHROPTS 3 bytes EBCDIC "n,y" - 002C VSAM Index SHROPTS 3 bytes EBCDIC "n,y" - 002D VSAM Index Space Type 9 bytes EBCDIC text string - 002E VSAM Index Space Primary 9 bytes EBCDIC num_value left-justified - 002F VSAM Index Space Secondary 9 bytes EBCDIC num_value left-justified - 0030 VSAM Index CISIZE 5 bytes EBCDIC num_value left-justified - 0031 VSAM Index IMBED 1 byte flag - 0032 VSAM Index Ordered Flag 1 byte flag - 0033 VSAM REPLICATE Flag 1 byte flag - 0034 VSAM Index REUSE Flag 1 byte flag - 0035 VSAM Index WRITECHK Flag 1 byte flag Retired with PKZIP 5.0 + - 0036 VSAM Owner 8 bytes EBCDIC text string - 0037 VSAM Index Owner 8 bytes EBCDIC text string - 0038 Reserved - 0039 Reserved - 003A Reserved - 003B Reserved - 003C Reserved - 003D Reserved - 003E Reserved - 003F Reserved - 0040 Reserved - 0041 Reserved - 0042 Reserved - 0043 Reserved - 0044 Reserved - 0045 Reserved - 0046 Reserved - 0047 Reserved - 0048 Reserved - 0049 Reserved - 004A Reserved - 004B Reserved - 004C Reserved - 004D Reserved - 004E Reserved - 004F Reserved - 0050 Reserved - 0051 Reserved - 0052 Reserved - 0053 Reserved - 0054 Reserved - 0055 Reserved - 0056 Reserved - 0057 Reserved - 0058 PDS/PDSE Member TTR Info. 6 bytes Big Endian - 0059 PDS 1st LMOD Text TTR 3 bytes Big Endian - 005A PDS LMOD EP Rec # 4 bytes Big Endian - 005B Reserved - 005C Max Length of records 2 bytes Big Endian - 005D PDSE Flag 1 byte flag - 005E Reserved - 005F Reserved - 0060 Reserved - 0061 Reserved - 0062 Reserved - 0063 Reserved - 0064 Reserved - 0065 Last Date Referenced 4 bytes Packed Hex "yyyymmdd" - 0066 Date Created 4 bytes Packed Hex "yyyymmdd" - 0068 GZIP two words 8 bytes - 0071 Extended NOTE Location 12 bytes Big Endian - 0072 Archive device UNIT 6 bytes EBCDIC - 0073 Archive 1st Volume 6 bytes EBCDIC - 0074 Archive 1st VOL File Seq# 2 bytes Binary - -APPENDIX C - Zip64 Extensible Data Sector Mappings (EFS) --------------------------------------------------------- - - -Z390 Extra Field: - - The following is the general layout of the attributes for the - ZIP 64 "extra" block for extended tape operations. Portions of - this extended tape processing technology is covered under a - pending patent application. The use or implementation in a - product of certain technological aspects set forth in the - current APPNOTE, including those with regard to strong encryption, - patching or extended tape operations, requires a license from - PKWARE. Please contact PKWARE with regard to acquiring a license. - - - Note: some fields stored in Big Endian format. All text is - in EBCDIC format unless otherwise specified. - - Value Size Description - ----- ---- ----------- - (Z390) 0x0065 2 bytes Tag for this "extra" block type - Size 4 bytes Size for the following data block - Tag 4 bytes EBCDIC "Z390" - Length71 2 bytes Big Endian - Subcode71 2 bytes Enote type code - FMEPos 1 byte - Length72 2 bytes Big Endian - Subcode72 2 bytes Unit type code - Unit 1 byte Unit - Length73 2 bytes Big Endian - Subcode73 2 bytes Volume1 type code - FirstVol 1 byte Volume - Length74 2 bytes Big Endian - Subcode74 2 bytes FirstVol file sequence - FileSeq 2 bytes Sequence - -APPENDIX D - Language Encoding (EFS) ------------------------------------- - -The ZIP format has historically supported only the original IBM PC character -encoding set, commonly referred to as IBM Code Page 437. This limits storing -file name characters to only those within the original MS-DOS range of values -and does not properly support file names in other character encodings, or -languages. To address this limitation, this specification will support the -following change. - -If general purpose bit 11 is unset, the file name and comment should conform -to the original ZIP character encoding. If general purpose bit 11 is set, the -filename and comment must support The Unicode Standard, Version 4.1.0 or -greater using the character encoding form defined by the UTF-8 storage -specification. The Unicode Standard is published by the The Unicode -Consortium (www.unicode.org). UTF-8 encoded data stored within ZIP files -is expected to not include a byte order mark (BOM). - -Applications may choose to supplement this file name storage through the use -of the 0x0008 Extra Field. Storage for this optional field is currently -undefined, however it will be used to allow storing extended information -on source or target encoding that may further assist applications with file -name, or file content encoding tasks. Please contact PKWARE with any -requirements on how this field should be used. - -The 0x0008 Extra Field storage may be used with either setting for general -purpose bit 11. Examples of the intended usage for this field is to store -whether "modified-UTF-8" (JAVA) is used, or UTF-8-MAC. Similarly, other -commonly used character encoding (code page) designations can be indicated -through this field. Formalized values for use of the 0x0008 record remain -undefined at this time. The definition for the layout of the 0x0008 field -will be published when available. Use of the 0x0008 Extra Field provides -for storing data within a ZIP file in an encoding other than IBM Code -Page 437 or UTF-8. - -General purpose bit 11 will not imply any encoding of file content or -password. Values defining character encoding for file content or -password must be stored within the 0x0008 Extended Language Encoding -Extra Field. - -Ed Gordon of the Info-ZIP group has defined a pair of "extra field" records -that can be used to store UTF-8 file name and file comment fields. These -records can be used for cases when the general purpose bit 11 method -for storing UTF-8 data in the standard file name and comment fields is -not desirable. A common case for this alternate method is if backward -compatibility with older programs is required. - -Definitions for the record structure of these fields are included above -in the section on 3rd party mappings for "extra field" records. These -records are identified by Header ID's 0x6375 (Info-ZIP Unicode Comment -Extra Field) and 0x7075 (Info-ZIP Unicode Path Extra Field). - -The choice of which storage method to use when writing a ZIP file is left -to the implementation. Developers should expect that a ZIP file may -contain either method and should provide support for reading data in -either format. Use of general purpose bit 11 reduces storage requirements -for file name data by not requiring additional "extra field" data for -each file, but can result in older ZIP programs not being able to extract -files. Use of the 0x6375 and 0x7075 records will result in a ZIP file -that should always be readable by older ZIP programs, but requires more -storage per file to write file name and/or file comment fields. - - - - diff --git a/doc/Changes.txt b/docs/Changes.txt similarity index 100% rename from doc/Changes.txt rename to docs/Changes.txt diff --git a/docs/SharpZipLibCodeMap.dgml b/docs/SharpZipLibCodeMap.dgml new file mode 100644 index 000000000..15a028613 --- /dev/null +++ b/docs/SharpZipLibCodeMap.dgml @@ -0,0 +1,413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/future/ARCHIVES.TXT b/docs/future/ARCHIVES.TXT new file mode 100644 index 000000000..7b2b7ab73 --- /dev/null +++ b/docs/future/ARCHIVES.TXT @@ -0,0 +1,1346 @@ + + + [[[[[[[[[ ARCHIVE FORMATS AND DATA ]]]]]]]]] + + (C) 1989 Raymond Clay + Permision to freely distribute and modify + is granted so long as credit is given + and all of the text through the disclaimer + is retained and unchanged + + October 31, 1989 + +If you want to submit corrections, changes or source code (in plain ASCII), +you can reach me via: + + + CIS : 74730,1344 + GEnie : R.CLAY1 + AppleLink : Raymond6 + StarText : 209287 511 bytes, < 128k DOS 3.3 256 + $3 > 129k HFS 524 + $5 extended file + $D subdirectory + +20 NXCRTIM HEX 000000 ;file creation time and date +23 NXCRDAT HEX 0000000000 +28 NXMDTIM HEX 000000 ;time and date file last modified +2B NXMDDAT HEX 0000000000 +30 NXARCTIM HEX 000000 ;time and date file archived +33 NXARCDAT HEX 0000000000 + . + . + +Any other attributes are added here. NXATRBCNT points to the NXFNL, which +is always the last attribute. + + . + . +NXATRBCNT-2 + NXFNL DW 0000 ;filename length + + +FILENAME SECTION +---------------- + +NXFNL+2 + NXFILE DS NXFNL ;Filename, partial pathname or disk + ;volume name. Names ported across + ;systems may have illegal characters + ;or characteristics. + + + + + + + + + + Page 12 + + +THREAD SECTION +-------------- + +Thread records are 16 byte records which immediately follow the filename and +describe the types of data structures which are included with a given record. +The number of threads is in the attribute section under NXNUMTHR. + + +A thread record can be represented as follows: + +OFFSET LABEL TYP VALUE DESCRIPTION +------ ----------- ---- ----------- ---------------------------------- +00 THRCLASS DW 0000 ;describes the class of the thread + + 0000 CLS_MSG + 0001 CLS__CNTRL + 0002 CLS_DATA + 0003 CLS_SPRSE + +02 THRFRMT DW 0000 ;format of the data within the thread + + 0000 ;Uncompressed + 0001 ;SQueezed (SQ/USQ) + 0002 ;Dynamic LZW [ShrinkIt] + 0003 + . ;RESERVED, contact the author + FFFF + +04 THRKIND DW 0000 ;describes data in thread + + if THRCLS = and THRKIND = THEN THE THREAD CONTAINS: + ---------------- -------------- --------------------------- + CLS_MSG 0000 ASCII text + all others undefined + + CLS_CNTRL 0000 create directory + all others undefined + + CLS_DATA 0000 data_fork of file + 0001 disk image + 0002 resource_fork of file + all others undefined + +06 DS 2 +08 THREOF HEX 00000000 ;length of the uncompressed thread +0C THRCMPEOF HEX 00000000 ;length of the compressed thread + +POSITIONING IN FILE +------------------- + +Start of the thread list = (beginning of header) + NXATRBCNT + NXFNL + +End of the thread list = (beginning of header) + NXATRBCNT + NXFNL + + (16 * NXNUMTHR) + +Start of a data_thread = (beginning of header) + NXATRBCNT + NXFNL + + (16 * NXNUMTHR) + (THRCMPEOF of all threads + in the thread list which are not data prior + to finding a CLS_DATA = 0000) + + + + + Page 13 + + +Start of a resource_thread = (beginning of header) + NXATRBCNT + NXFNL + + (16 * NXNUMTHR) + (THRCMPEOF of all the + threads in the thread list which are not + resources prior to finding a + CLS_DATA = 0002) + +Next record = (beginning of header) + NXATRBCNT + NXFNL + + (16 * NXNUMTHR) + (THRCMPEOF of each thread) + + ************************************************** + + + PACKIT + ====== + +System of Origin : Macintosh + +FILE HEADER +----------- + +OFFSET LABEL TYP VALUE DESCRIPTION +------ ----------- ---- ----------- ---------------------------------- +00 PITFLN HEX 00 ;filename length +01 PITFNAM DS 63 ;filename +40 PITTYP HEX 00000000 ;file type +44 PITCRT HEX 00000000 ;Creator +48 PITFFLG DW 0000 ;Finder flags +4C PITLOK DW 0000 ;locked? +4E PITDSIZ HEX 00000000 ;data fork uncompressed size +52 PITRSIZ HEX 00000000 ;resource fork uncompressed size +56 PITCDSIZ HEX 00000000 ;data fork compressed size +5A PITCRSIZ HEX 00000000 ;resource fork compressed size +5E PITCRC DW 0000 ;CRC + + ************************************************** + + + STUFFIT + ======= + +System of Origin : Macintosh + +Original author : Raymond Lau + +FILE FORMAT +----------- + + Master Header + file header 1 + file 1 resource fork + file 1 data fork + file header 2 + file 2 resource fork + file 2 data fork + . + . + file header n + file n resource fork + file n data fork +EOF + + + + Page 14 + + +MASTER HEADER +------------- + +OFFSET LABEL TYP VALUE DESCRIPTION +------ ----------- ---- ----------- ---------------------------------- +00 SITHSIG ASC 'SIT!' ;STUFFIT archive signature +04 SITHNUM DW 0000 ;number of files in archive +06 SITHLEN HEX 00000000 ;length of entire archive incl hdr +0A SITHID2 ASC 'rLau' ;authors name - R. Lau +0E SITHVER DB 00 ;version number +0F DS 7 ;reserved + + +FILE HEADER +----------- + +OFFSET LABEL TYP VALUE DESCRIPTION +------ ----------- ---- ----------- ---------------------------------- +00 SITFRCMP DB 00 ;rsrc fork compression method +01 SITFDCMP DB 00 ;data fork compression method +02 SITFNL DB 00 ;file name length +03 SITFNAM DS $3F ;filename +41 SITFTYP DB 00000000 ;filetype +45 SITFCR DB 00000000 ;file creator +49 SITFFFL DW 0000 ;Finder flags +4B SITFCRD HEX 00000000 ;creation date +4F SITFMDD HEX 00000000 ;modification date +53 SITFRLN HEX 00000000 ;uncompressed resource fork length +57 SITFDLN HEX 00000000 ;uncompressed data fork length +5B SITFCRLN HEX 00000000 ;compressed resource fork length +5F SITFCDLN HEX 00000000 ;compressed data fork length +61 SITFRCRC DW 0000 ;resource fork CRC +63 SITFDCRC DW 0000 ;data fork CRC +65 SITFRPAD DB 00 ;pad bytes for encrypted files, +66 SITFDPAD DB 00 ;resource and data forks +6A DS 4 ;reserved +6E SITFHCRC DW 0000 ;CRC of file header + + + STUFFIT METHODS + + NAME METHOD DESCRIPTION + ----------- ------ -------------------------------------------- + noComp 0 uncompressed + rleComp 1 RLE compression + lzwComp 2 LZW compression, 18k buffer, 14 bit code size + hufComp 3 Huffman compression + encrypted 16 bit set if encrypted. ex: encrypted+lzwComp + startFolder 32 marks start of a new folder + endFolder 33 marks end of the last folder started + + + + + + + + + + + + + + Page 15 + + +POSITIONING IN FILE +------------------- + +First File Header = SITHSIG + $15 + +Begining of Resource Fork = SITFRCMP + $6F + +Begining of Data Fork = Begining of Resource Fork + SITFCRLN + +Next File Header = Begining of previous Data Fork + SITFCDLN + or + = Previous File Header + $6F + SITFCRLN + SITCDLN + + ************************************************** + + + ZIP + === + +System of Origin : IBM + +Original author : Phil Katz + +FILE FORMAT +----------- + + +Files stored in arbitrary order. Large zipfiles can span multiple +diskette media. + + Local File Header 1 + file 1 extra field + file 1 comment + file data 1 + Local File Header 2 + file 2 extra field + file 2 comment + file data 2 + . + . + . + Local File Header n + file n extra field + file n comment + file data n + Central Directory + central extra field + central comment + End of Central Directory + end comment +EOF + + + + + + + + + + + + + Page 16 + + +LOCAL FILE HEADER +----------------- + +OFFSET LABEL TYP VALUE DESCRIPTION +------ ----------- ---- ----------- ---------------------------------- +00 ZIPLOCSIG HEX 04034B50 ;Local File Header Signature +04 ZIPVER DW 0000 ;Version needed to extract +06 ZIPGENFLG DW 0000 ;General purpose bit flag +08 ZIPMTHD DW 0000 ;Compression method +0A ZIPTIME DW 0000 ;Last mod file time (MS-DOS) +0C ZIPDATE DW 0000 ;Last mod file date (MS-DOS) +0E ZIPCRC HEX 00000000 ;CRC-32 +12 ZIPSIZE HEX 00000000 ;Compressed size +16 ZIPUNCMP HEX 00000000 ;Uncompressed size +1A ZIPFNLN DW 0000 ;Filename length +1C ZIPXTRALN DW 0000 ;Extra field length +1E ZIPNAME DS ZIPFNLN ;filename +-- ZIPXTRA DS ZIPXTRALN ;extra field + +CENTRAL DIRECTORY STRUCTURE +--------------------------- + +OFFSET LABEL TYP VALUE DESCRIPTION +------ ----------- ---- ----------- ---------------------------------- +00 ZIPCENSIG HEX 02014B50 ;Central file header signature +04 ZIPCVER DB 00 ;Version made by +05 ZIPCOS DB 00 ;Host operating system +06 ZIPCVXT DB 00 ;Version needed to extract +07 ZIPCEXOS DB 00 ;O/S of version needed for extraction +08 ZIPCFLG DW 0000 ;General purpose bit flag +0A ZIPCMTHD DW 0000 ;Compression method +0C ZIPCTIM DW 0000 ;Last mod file time (MS-DOS) +0E ZIPCDAT DW 0000 ;Last mod file date (MS-DOS) +10 ZIPCCRC HEX 00000000 ;CRC-32 +14 ZIPCSIZ HEX 00000000 ;Compressed size +18 ZIPCUNC HEX 00000000 ;Uncompressed size +1C ZIPCFNL DW 0000 ;Filename length +1E ZIPCXTL DW 0000 ;Extra field length +20 ZIPCCML DW 0000 ;File comment length +22 ZIPDSK DW 0000 ;Disk number start +24 ZIPINT DW 0000 ;Internal file attributes + + LABEL BIT DESCRIPTION + ----------- --------- ----------------------------------------- + ZIPINT 0 if = 1, file is apparently an ASCII or + text file + 0 if = 0, file apparently contains binary + data + 1-7 unused in version 1.0. + +26 ZIPEXT HEX 00000000 ;External file attributes, host + ;system dependent +2A ZIPOFST HEX 00000000 ;Relative offset of local header + ;from the start of the first disk + ;on which this file appears +2E ZIPCFN DS ZIPCFNL ;Filename or path - should not + ;contain a drive or device letter, + ;or a leading slash. All slashes + ;should be forward slashes '/' +-- ZIPCXTR DS ZIPCXTL ;extra field +-- ZIPCOM DS ZIPCCML ;file comment + + + Page 17 + + +END OF CENTRAL DIR STRUCTURE +---------------------------- + +OFFSET LABEL TYP VALUE DESCRIPTION +------ ----------- ---- ----------- ---------------------------------- +00 ZIPESIG HEX 06064B50 ;End of central dir signature +04 ZIPEDSK DW 0000 ;Number of this disk +06 ZIPECEN DW 0000 ;Number of disk with start central dir +08 ZIPENUM DW 0000 ;Total number of entries in central dir + ;on this disk +0A ZIPECENN DW 0000 ;total number entries in central dir +0C ZIPECSZ HEX 00000000 ;Size of the central directory +10 ZIPEOFST HEX 00000000 ;Offset of start of central directory + ;with respect to the starting disk + ;number +14 ZIPECOML DW 0000 ;zipfile comment length +16 ZIPECOM DS ZIPECOML ;zipfile comment + + +ZIP VALUES LEGEND +----------------- + + HOST O/S + + VALUE DESCRIPTION VALUE DESCRIPTION + ----- -------------------------- ----- ------------------------ + 0 MS-DOS and OS/2 (FAT) 5 Atari ST + 1 Amiga 6 OS/2 1.2 extended file sys + 2 VMS 7 Macintosh + 3 *nix 8 thru + 4 VM/CMS 255 unused + + + GENERAL PURPOSE BIT FLAG + + LABEL BIT DESCRIPTION + ----------- --------- ----------------------------------------- + ZIPGENFLG 0 If set, file is encrypted + or 1 If file Imploded and this bit is set, 8K + ZIPCFLG sliding dictionary was used. If clear, 4K + sliding dictionary was used. + 2 If file Imploded and this bit is set, 3 + Shannon-Fano trees were used. If clear, 2 + Shannon-Fano trees were used. + 3-4 unused + 5-7 used internaly by ZIP + + Note: Bits 1 and 2 are undefined if the compression method is + other than type 6 (Imploding). + + + + + + + + + + + + + + + Page 18 + + + COMPRESSION METHOD + + NAME METHOD DESCRIPTION + ----------- ------ -------------------------------------------- + Stored 0 No compression used + Shrunk 1 LZW, 8K buffer, 9-13 bits with partial clearing + Reduced-1 2 Probalistic compression, L(X) = lower 7 bits + Reduced-2 3 Probalistic compression, L(X) = lower 6 bits + Reduced-3 4 Probalistic compression, L(X) = lower 5 bits + Reduced-4 5 Probalistic compression, L(X) = lower 4 bits + Imploded 6 2 Shanno-Fano trees, 4K sliding dictionary + Imploded 7 3 Shanno-Fano trees, 4K sliding dictionary + Imploded 8 2 Shanno-Fano trees, 8K sliding dictionary + Imploded 9 3 Shanno-Fano trees, 8K sliding dictionary + + + EXTRA FIELD + + OFFSET LABEL TYP VALUE DESCRIPTION + ------ ----------- ---- ---------- ---------------------------- + 00 EX1ID DW 0000 ;0-31 reserved by PKWARE + 02 EX1LN DW 0000 + 04 EX1DAT DS EX1LN ;Specific data for individual + . ;files. Data field should begin + . ;with a s/w specific unique ID + EX1LN+4 + EXnID DW 0000 + EXnLN DW 0000 + EXnDAT DS EXnLN ;entire header may not exceed 64k + + ************************************************** + + + ZOO + === + +System of Origin : IBM + +Original author : Rahul Dhesi + +FILE FORMAT +----------- + + Master Header + file 1 header + file 1 + file 2 header + file 2 + . + . + file n header + file n +EOF + + + + + + + + + + + Page 19 + + +MASTER HEADER +------------- + +OFFSET LABEL TYP VALUE DESCRIPTION +------ ----------- ---- ----------- ---------------------------------- +00 DS 20 +14 ZOOSIG HEX A7DCFDC4 ;File signature +18 ZOO1PTR HEX 00000000 ;pointer to 1st header +1C ZOO? HEX 00000000 ;? +20 ZOOMVER DB 00 ;version making archive +21 ZOOMIN DB 00 ;minimum version needed to extract + + +FILE HEADER +----------- + +OFFSET LABEL TYP VALUE DESCRIPTION +------ ----------- ---- ----------- ---------------------------------- +00 ZOOFSIG HEX A7DCFDC4 ;signature +04 ZOOFTYP DB 00 ;? +06 ZOOFCMP DB 00 ;Compression method +08 ZOOFNXH HEX 00000000 ;Nxt hdr ofst frm Start of ZOO file +0A ZOOFCUR HEX 00000000 ;Offset of this hdr +0E ZOOFDAT DW 0000 ;Last mod file date (MS-DOS) +10 ZOOFTIM DW 0000 ;Last mod file time (MS-DOS) +12 ZOOFCRC DW 0000 ;CRC-16 +14 ZOOFOSZ HEX 00000000 ;Uncompressed size +18 ZOOFNSZ HEX 00000000 ;Compressed size +1C ZOOFMVER DB 00 ;version that made this file +1D ZOOFMIN DB 00 ;minimum version needed to extract +1E Z00FDEL DB 00 ;1 if file deleted from archive +1F ZOOFCMTP HEX 00000000 ;pointer to comment, 0 if none +23 ZOOFCMTL DW 0000 ;length of comment +25 ZOOFNAM DS 13 ;filename + + +ZOO METHOD +---------- + + NAME METHOD DESCRIPTION + ----------- ------ -------------------------------------------- + Stored No compression used + Crunched Packing, LZW, 4K buffer, var len (9-12 bits) + +POSITIONING IN FILE +------------------- + +Begining of 1st File header = Begining of File + ZOO1PTR + or + = Begining of File + $21 + +Begining of File Data = Begining of File Header + $31 + +Begining of Next File = Begining of File + ZOOFNXH + +Begining of File Comment = Begining of File Header + ZOOFCMTP + + ************************************************** + + + + + + Page 20 + + + TIME VALUES + =========== + +MS-DOS TIME FORMAT +------------------ + + LABEL BIT DESCRIPTION + ----------- --------- ----------------------------------------- + DATE 15-9 Year + 8-5 Month + 4-0 Day (all zeroes means no date) + + TIME 15-11 Hours (military) + 10-5 Minutes + 4-0 Seconds + + +ProDOS/SOS TIME FORMAT (APPLE) +------------------------------ + + LABEL BIT DESCRIPTION + ----------- --------- ----------------------------------------- + DATE 15-9 Year (0-99) + 8-5 Month + 4-0 Day + + TIME 15-8 Hour (military time) + 7-0 Minutes + + ************************************************** + + + EXTENDED FILES + -------------- + +Extended files are a storage format used by a variety of operating +systems. The filename information points to a file that points to 2 other +files known as the DATA FORK and the RESOURCE FORK. + +The resource fork contains information about, and/or for the use of, the +data fork. In porting amongst systems the resource fork is probably of +no use. + +The data fork contains the actual file. + + ************************************************** + + + FILENAMES + --------- + +File name lengths, legal characters and format vary amongst the various +operating systems. MS-DOS allows a wider variety of characters while the +Apple operating systems allow longer names with no set format (no +extensions). Any program must be ready to convert a filename into the +current operating system format as well as handle any paths (either by +creating or ignoring them). + + + + + + + Page 21 + + +A suggestion would be to use a more universal standard for the filenames +of files that are likely to be ported (ie; Text, ASCII Source, GIF, ASCII +data files, etc) while making no special effort with executable code +(including tokenized BASIC) filenames. + +Such a standard might be: + + a filename of no more than 13 or less than 6 characters + legal characters A-Z (all uppercase) the '.' and 0-9 + periods to be used only once in a file to make an MS-DOS + type extension (ie; .TXT, .DOC, etc) + the filename MUST start with an alphabetic character (A-Z) + +********************************************************************** + + +Information taken from files by Alex Bamdad, Rahul Dhesi, Jim Dorsey, Don +Elton, Colin James, Phil Katz, Raymond Lau, Gary Little, Andrew Nicholas, +Haruhiko Okumura, Martin Peckham, Mike Sax, Tim Swihart and probably +others. + diff --git a/docs/future/FILEFMTS.DOC b/docs/future/FILEFMTS.DOC new file mode 100644 index 000000000..5005033e6 --- /dev/null +++ b/docs/future/FILEFMTS.DOC @@ -0,0 +1,162 @@ + + Definition of the data types used in the file format list + +In the file format list, several short mnemonics are used to describe +the structure of the data stored. Here I describe the structure (and +possible conversion) between some of these types. As some types have +different sizes across the platforms, for most types the byte order and +bit size is given to describe it. + +ASCIIZ A sequence of characters(->char), terminated + with the special character with the value 0. + Note that ASCIIZ strings as most structures on + Intel machines should not be larger than + 64Kb due to the ancient segmentation used. +BCD Binary coded decimal + A decimal number is converted into a hexadecimal number + which has the same digits as the decimal number. + (10d becomes 10h, 21d becomes 21h) +Bitmap If a value is declared as bitmapped, that means that + every bit in this value might have a different meaning. + The bytes are numbered from right to left, the least + significant bit has the number 0. After the bit number, + there are either two statements, separated by a + slash("/"), which are the two meanings if the bit is + set / not set, or one single statement, which is the + meaning of this bit, if it is set. +Byte 8 bit unsigned number. Smallest unit a record + consists of. All offsets are in the unit bytes. + (0-255) +Char Synonym for byte, most values are between 32 and + 255. (#0-#255) +DWord 32 bit signed number. Well, maybe some of the + formats use a DWord which is a 32 bit unsigned + number, but as files tend not to be greater than + 2GB, this won't be my concern. To convert + between Intel and Motorola format, you have to + swap bytes #2 & #3 and bytes #1 & #4.(-2Gb-+2Gb) +Int Integer. Signed 16-bit number. + (-32767-+32767) +LString A string which is preceeded by the length. Also + named "counted" string. Used by most Pascal + implementations Maximum length is 255 bytes, but it can + contain any char. +Nybble The upper or lower four bits of a byte. A nybble + is a single hex digit and can have values from + 0 to 15. A signed nybble can have values from + -8 to 7 with bit 3 being the sign bit. +Paragraph A multiple of 16. A paragraph was the resolution of the + Intel chip 64K segments. +Word 16 bit unsigned number. Note that byte order is + important, wether you have a Motorola machine or + an Intel one. Conversion between the two formats + is simply by swapping byte #1 with byte #2. + (0-65535) + + How to identify different files + +While searching for different file formats, I found the following programs +helpful to gather information about different files. They all are DOS programs +since I'm not familiar with other platforms (except Windows). Most of them +should be available on SimTel CDs or via FTP at ftp.cdrom.com, except for my +program TF, which is still in beta. + +LIST.COM v9.0a by Vernon Buerg + List is a file lister which supports both text and hex-view. + +HIEW.EXE v4.18 by Sen + Another file lister with build-in disassembler. + +FILE.EXE v2.0 by Felix von Leitner + File is a file identification program. + +Q.COM v3.01 by SemWare + QEdit is the editor I'm editing the list with. + +TF.EXE v0.38 by me + The program that started it all. A "simple" file identification + program - no more, since it has grown too big by now. + Still unreleased, since it is not really extensible yet. + + The file formats list meta list ;) + +The file format list uses a certain format to make it readable by programs which +convert it into the WinHelp format or create program structures out of the +lists. This format is very similar to the format used by Ralf Brown in his PC +interrupt list but was extended by me to accomodate for the specific needs of +this list : + +Each topic in the list is delimited by a line of 45 chars, in which the +first 8 contain the char '-'. After these, there follows one character which +contains the type of topic. The different topics are described in the list +itself, the char '!' denotes an information topic - like the list of chars and +their meaning. After the topic identifier, there follows another '-' char and +then the topic name, not containing any '-' chars. After the topic name, there +may be some other descriptors like for Motorola byte ordering, guesswork marking +or other purposes, see the main list for further information. The line is ended +with at least one '-' char. Take the following prototype : + +--------?-TEST------------------------------ + +OFFSET Count TYPE Description +EXTENSION: +OCCURENCES: +PROGRAMS: +REFERENCE: +SEE ALSO: +VALIDATION: + +Sub-topics like different records are mostly delimited by three dashes ('-'). +I suggest folding them up and making them available as a popup window. + +Tables have the following format : +(see table 0000) +for a table reference and +(Table 0000) +for the beginning of a table. The end of a table is undefined (yet). + + + A primer on file formats + + Abbrevations +Throughout the list, many abbrevations are used, some in the reference +section. Here some are explained : + +c't +The c't is a german computer magazine, which developed the Borland +Pascal for OS/2 patch. They release source code in files called +CTmmyy.*. Note that comments in the source code and the language in +the issues tend to be german :-) + +DDJxxyy +(Doctor Dobb's Journal) +The DDJ is a monthly publication by M&T/US which is intended for the +professional programmer. The four digits after the name indicate the +month/year of the issue referred to. Most of the sourcecode published +in the issue is available electronically on Compu$erve and other BBSes. +The files have the name DDJyymm. + +PDN +Programmer's Distribution Net +A network dedicated to the distribution of source code useful to +programmers. Often linked with Fido-nodes. + +Contributions to this list were made by : + Ralf Brown (The .EXE file formats from the INTERRUPT List, general layout) + David Dilworth (david.dilworth@sierraclub.org) + Daniel Dissett (ddissett@netcom.com) + Marcus Groeber (marcusg@ph-cip.uni-koeln.de) + Darrel Hankerson (hankedr@mail.auburn.edu) + Carl Hauser (chauser.parc@xerox.com) + Jouni Miettunen (jon@stekt.oulu.fi) + Jan Nicolai Langfeldt (janl@ifi.uio.no) + Mark Ouellet (Telix .FON structures) + Greg Roelofs (roe2@midway.uchicago.edu) + Robert Rothenburg Walking-Owl (wlkngowl@unix.asb.com) + Jesus Villena (CONVERT.EXE, a digital sample conversion program) + Christos Zoulas (christos@deshaw.com) + JAL / Nostalgia + David McDuffee, (75530,2626@compuserve.com) + +Information gleaned from other programs : + Formats for Word and WordPerfect (Selke's filetype) diff --git a/docs/future/FILEFMTS.LST b/docs/future/FILEFMTS.LST new file mode 100644 index 000000000..0669ac756 --- /dev/null +++ b/docs/future/FILEFMTS.LST @@ -0,0 +1,7496 @@ +File format list Release 3.00 Last change 02/04/96 +This compilation is Copyright (c) 1994,2002 Max Maischein +--------!-CONTACT_INFO---------------------- +If you notice any mistakes or omissions, please let me know! It is only +with YOUR help that the list can continue to grow. Please send +all changes to me rather than distributing a modified version of the list. + +This file has been authored in the style of the INTERxxy.* file list +by Ralf Brown, and uses almost the same format. + +Please read the file FILEFMTS.1ST before asking me any questions. You may find +that they have already been addressed. + + Max Maischein + +corion@corion.net +Corion on #coders@IRC +--------!-DISCLAIMER------------------------ +DISCLAIMER: THIS MATERIAL IS PROVIDED "AS IS". I verify the information +contained in this list to the best of my ability, but I cannot be held +responsible for any problems caused by use or misuse of the information, +especially for those file formats foreign to the PC, like AMIGA or SUN file +formats. If an information it is marked "guesswork" or undocumented, you +should check it carefully to make sure your program will not break with +an unexpected value (and please let me know whether or not it works +the same way). + +Information marked with "???" is known to be incomplete or guesswork. + +Some file formats were not released by their creators, others are regarded +as proprietary, which means that if your programs deal with them, you might +be looking for trouble. I don't care about this. +--------!-FLAGS----------------------------- +One or more letters may follow the file format ID; they have the following +meanings: + Cx - Charset used : + 7 - Unix 7-bit characters + A - Amiga charset (if there is one) + E - EBDIC character format + U - Unicode character set + W - Windows char set + Default is the 8-Bit IBM PC-II Charset. Note that Microsoft + introduced codepages which might be relevant with other + programs. + G - guesswork, incomplete, unreliable etc. + M - Motorola byte order + Default is Intel byte order + O - obsolete, valid only for version noted below + X - Synonym topic. See topic named under see also. +--------!-CATEGORIES------------------------ +The ninth column of the divider line preceding an entry usually contains a +classification code for the application that uses those files. + +The codes currently in use are: + ! - User information ( not really a file format ) + A - Archives (ARC,LZH,ZIP,...) + a - Animations (CEL, FLI, FLT,...) + B - Binary files for compilers etc. (OBJ,TPU) + H - Help file (HLP,NG) + I - Images, bit maps (GIF,BMP,TIFF,...) + D - Data support files (CPI,FON,...) + E - Executable files (EXE,PIF) + f - Generic file format. RIFF and IFF are generic file formats. + F - Font files (TTF) + G - General graphics file + M - Module music file (MIDI,MOD,S3M,...) + R - Resource data files (RES) + S - Sound files (WAV,VOC,ZYX) + T - Text files (DOC,TXT) + W - Spreadsheet and related (WKS) + X - Database files (DBF) +--------!-FIELDS---------------------------- +After a format description, you will sometimes find other keywords. The +meanings of these are : + EXTENSION: + This is the default extension of files of the given type. + On DOS systems, most files have a 3 letter extension. + On Amiga systems, the files are prefixed with something. + The DOS extensions are all uppercase, extensions for other systems + are in lower case chars. On other systems, which do not have the con- + cept of extensions, as the MAC, this is the file type. + OCCURENCES: + Where you are likely to encounter those files. This specifies + machines (like PC,AMIGA) or operating systems (like UNIX). + PROGRAMS: + Programs which either create, use or convert files of this format. + Some might be used for validation or conversion. + REFERENCE: + A reference to a file or an article in a magazine which is mandatory + or recommended for further understanding of the matter. + SEE ALSO: + A cross reference to a topic which might be interesting as well. + VALIDATION: + Methods to validate that the file you have is not corrupt. Normally + this is a method to check the theoretical file size against the + real filesize. Some file formats allow no reliable validation. +--------!-FORMAT---------------------------- + The block oriented files are organized in some other fashion, since the + order of blocks is at best marginally obligatory. + + Each block type starts with the block ID (eg. RIFFblock for a RIFF file) and + in square brackets the character value of the ID field (eg. [WAVE] for RIFF + WAVe sound files). The block itself is descripted in the format description, + that means you will have to look after RIFF or FORM. In the record + description, the header information is omitted ! + + If a record is descripted, the record ends when the next offset is given. + + Bitmapped values have a description for each bit. The value left of the + slash ("/") is for the bit not set (=0), the right sided value applies + if the bit is set. + + A note on the tables section. The tables were added as they were introduced + into Ralf Browns interrupt list - so not everything was pressed into a table. + The tables (should) have unique numbers, but they sure are out of order ! +--------!-MACHINES-------------------------- + Machines that use Intel byte ordering + PC + Machines that use Motorola byte ordering + AMIGA, ATARI ST, MAC, SUN + +--------M-669------------------------------- +The .669 format is a module format for digital music. + +OFFSET Count TYPE Description +0000h 1 word ID=6669h +0002h 108 byte ASCII song message +006Eh 1 byte Number of saved samples (0-40h) + ="NOS" +006Fh 1 byte Number of saved patterns (0-80h) + ="NOP" +0070h 1 byte Loop order number +0071h 128 byte Order list +00F1h 128 byte Tempo list for patterns +0171h 128 byte Break location list for patterns +01F1h "NOS" rec Sample data + The sample data is in the file + for "NOS" + 13 byte ASCIIZ filename of instrument + 1 dword Length of instrument sample + 1 dword Offset of beginning of loop + 1 dword Offset of end of loop +01F1h+ "NOP"*600 rec The note patterns + "NOS"*19h Those patterns are repeated for each row, + and the array of these is repeated 64 times + for each pattern. + 3 byte Note(see table 0000) +01F1h+ ? byte Sample data (unsigned) + "NOS"*0x19+ + "NOP"*0x600 + +(Table 0000) +669 Note format +Each note looks like this : +BYTE[0]: BYTE[1]: BYTE[2]: +nnnnnnii iiiivvvv ccccdddd + + n : note value + i : 6-bit instrument number + v : 4-bit volume + c : command data (Protracker format mapped) : + 0 = a + 1 = b + 2 = c + 3 = d + 4 = e + 5 = f + d : command value (Protracker format) + +Special values for byte 0 : + 0FEh : no note, only volume + 0FFh : no note or no command, if byte 2 = 0FFh + +EXTENSION:669 +OCCURENCES:PC +SEE ALSO:MOD +PROGRAMS:669 Mod Composer, DMP +VALIDATION: +--------S-8SVX-MG--------------------------- +The 8SVX files are IFF files used for digital audio data. The format of +the VHDR block is complete guesswork. These files use Motorola byte order. +The 8SVX file format is fixed to 8-bit mono sample data - at least GoldWave +does not support saving files in any other format than 8-bit mono. + +FORMblock [VHDR] +This is the sample information block. The normal size is 20 bytes. +OFFSET Count TYPE Description +0000h 1 dword Sampling rate of digital data in Hz. + This count seems not to be too accurate, + at least GoldWave v2.0 creates different + rates for Wave and 8SVX files. +0004h 4 dword Other data, unknown + +FORMblock [BODY] +This block contains the raw sample data, maybe the usual IFF compression was +used. The details of both the compression and the information about the IFF +format are unknown to me. +EXTENSION:IFF +OCCURENCES:PC,Amiga +PROGRAMS:GoldWave +SEE ALSO:IFF,WAVE +VALIDATION: +--------S-AIFC-MG--------------------------- +The AIFC files seem to be a variation of the AIFF files - but I don't know +anything about them. +EXTENSION:IFF +SEE ALSO:AIFF +--------S-AIFF-MG--------------------------- +The Audio Interchangeable File Format files are digital audio files +stored in the IFF format; the samples are stored in signed PCM. The header +block is [AIFF], different subblocks are : + +[AUTH] +The authors information; optional +[COMM] +This record stores information about the sampled data : +OFFSET Count TYPE Description +0000h 1 word ??? number of channels ??? + ??? number of instrument samples ??? +0002h 1 dword Sample length +0006h 1 dword lower frequency +000Ah 1 dword maximum frequency +000Dh 1 dword ??? +[MARK] +[NAME] +The name of the instrument / sample +[SSND] +The stored sample data. + +Further information wanted. +EXTENSION:AIF,IFF +--------E-AMIGA EXECUTABLE-MG--------------- +All Amiga executables I've seen start with this signature. Of course the +bytes are in Motorola byte order, as you would exspect from a Motorola +based machine. This info here is based completely on my guesswork, maybe +somebody from the Amiga could help flesh out this part. + +OFFSET Count TYPE Description +0000h 1 dword ID=03F3h +EXTENSION:EXE +OCCURENCES:AMIGA +SEE ALSO: +VALIDATION: +--------M-AMS------------------------------- +The AMS format is a multichannel module format created by the X-Tracker (not +to be mistaken for he tracker of the same name by D-Lusion). +The X-Tracker by Extreme PC is a multichannel tracker that features 32 digital +channels, 64 MIDI channels, 255 samples, 64K patterns and positions. The tracker +is currently in beta status and not enough information is yet available yet. + +OFFSET Count TYPE Description + +EXTENSION: +OCCURENCES: +PROGRAMS: +REFERENCE: +SEE ALSO:MOD +VALIDATION: +--------A-ARC------------------------------- +The ARC files are archive files created by the SEA ARC program. The compression +has been superceded by more recent compression programs. Similar archives can +be created by the PAK and PkPAK programs. There have been many variations +and enhancements to the ARC format though not as many as to the TIFF format. + +You may have to use some (paranoid) checks to ensure that you actually are +processing an ARC file, since other archivers also adopted the idea of putting +a 01Ah byte at offset 0, namely the Hyper archiver. To check if you have a +Hyper-archive, check the next two bytes for "HP" or "ST" (or look below for +"HYP"). Also the ZOO archiver also does put a 01Ah at the start of the file, +see the ZOO entry below. +OFFSET Count TYPE Description +0000h 1 byte ID=1Ah +0001h 1 byte Compression method (see table 0001) +0002h 12 char File name +000Fh 1 dword Compressed file size +0013h 1 dword File date in MS-DOS format (see table 0009) +0017h 1 word 16-bit CRC +0019h 1 dword Original file size + ="SIZ" +(Table 0001) +ARC compression types + 0 - End of archive marker + 1 - unpacked (obsolete) - ARC 1.0 ? + 2 - unpacked - ARC 3.1 + 3 - packed (RLE encoding) + 4 - squeezed (after packing) + 5 - crunched (obsolete) - ARC 4.0 + 6 - crunched (after packing) (obsolete) - ARC 4.1 + 7 - crunched (after packing, using faster hash algorithm) - ARC 4.6 + 8 - crunched (after packing, using dynamic LZW variations) - ARC 5.0 + 9 - Squashed c/o Phil Katz (no packing) (var. on crunching) + 10 - crushed (PAK only) + 11 - distilled (PAK only) +12-19 - to 19 unknown (ARC 6.0 or later) - ARC 7.0 (?) +20-29 - ?informational items? - ARC 6.0 +30-39 - ?control items? - ARC 6.0 + 40+ - reserved + +According to SEA's technical memo, the information and control items +were added to ARC 6.0. Information items use the same headers as archived +files, although the original file size (and name?) can be ignored. + +OFFSET Count TYPE Description +0000h 2 byte Length of header (includes "length" + and "type"?) +0002h 1 byte (sub)type +0003h ? byte data + +Informational item types as used by ARC 6.0 : + +Block type Subtype Description + 20 archive info + 0 archive description (ASCIIZ) + 1 name of creator program (ASCIIZ) + 2 name of modifier program (ASCIIZ) + + 21 file info + 0 file description (ASCIIZ) + 1 long name (if not MS-DOS "8.3" filename) + 2 extended date-time info (reserved) + 3 icon (reserved) + 4 file attributes (ASCIIZ) + + Attributes use an uppercase letter to signify the + following: + + R read access + W write access + H hidden file + S system file + N network shareable + + 22 operating system info (reserved) + +(Table 0009) +Format of the MS-DOS time stamp (32-bit) +The MS-DOS time stamp is limited to an even count of seconds, since the +count for seconds is only 5 bits wide. + + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 + |<---- year-1980 --->|<- month ->|<--- day ---->| + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + |<--- hour --->|<---- minute --->|<- second/2 ->| + +EXTENSION:ARC,PAK +OCCURENCES:PC +PROGRAMS:SEA ARC,PAK,PkPAK +SEE ALSO:HYP,ZOO +VALIDATION:FileSize="SIZ" +--------A-ARJ------------------------------- +The ARJ program by Robert K. Jung is a "newcomer" which compares well to PKZip +and LhArc in both compression and speed. An ARJ archive contains two types of +header blocks, one archive main header at the head of the archive and local +file headers before each archived file. + +OFFSET Count TYPE Description +0000h 1 word ID=0EA60h +0002h 1 word Basic header size (0 if end of archive) +0004h 1 byte Size of header including extra data +0005h 1 byte Archiver version number +0006h 1 byte Minimum version needed to extract +0007h 1 byte Host OS (see table 0002) +0008h 1 byte Internal flags, bitmapped : + 0 - no password / password + 1 - reserved + 2 - file continues on next disk + 3 - file start position field is available + 4 - path translation ( "\" to "/" ) +0009h 1 byte Compression method : + 0 - stored + 1 - compressed most + 2 - compressed + 3 - compressed faster + 4 - compressed fastest + Methods 1 to 3 use Lempel-Ziv 77 sliding window + with static Huffman encoding, method 4 uses + Lempel-Ziv 77 sliding window with pointer/ + length unary encoding. +000Ah 1 byte File type : + 0 - binary + 1 - 7-bit text + 2 - comment header + 3 - directory + 4 - volume label +000Bh 1 byte reserved +000Ch 1 dword Date/Time of original file in MS-DOS format +0010h 1 dword Compressed size of file +0014h 1 dword Original size of file +0018h 1 dword Original file's CRC-32 +001Ah 1 word Filespec position in filename +001Ch 1 word File attributes +001Eh 1 word Host data (currently not used) +? 1 dword Extended file starting position when used + (see above) + ? char ASCIIZ file name + ? char Comment +????h 1 dword Basic header CRC-32 +????h 1 word Size of first extended header (0 if none) + ="SIZ" +????h+"SIZ"+2 1 dword Extended header CRC-32 +????h+"SIZ"+6 ? byte Compressed file + +(Table 0002) +ARJ HOST-OS types + 0 - MS-DOS + 1 - PRIMOS + 2 - UNIX + 3 - AMIGA + 4 - MAC-OS (System xx) + 5 - OS/2 + 6 - APPLE GS + 7 - ATARI ST + 8 - NeXT + 9 - VAX VMS +EXTENSION:ARJ +OCCURENCES:PC +PROGRAMS:ARJ.EXE +REFERENCE: +SEE ALSO: +VALIDATION: +--------S-AU-MG----------------------------- +The AU files are digital audio files used by the Sun and NeXT +workstations. +Further information wanted. +OFFSET Count TYPE Description +0000h 4 char ID='.snd' +0004h 1 dword Offset of start of sample +0008h 1 dword Length of stored sample +000Ch 1 dword Sound encoding : + 1 - 8-bit ISDN u-law + 2 - 8-bit linear PCM (REF-PCM) + 3 - 16-bit linear PCM + 4 - 24-bit linear PCM + 5 - 32-bit linear PCM + 6 - 32-bit IEEE floating point + 7 - 64-bit IEEE floating point + 23 - 8-bit ISDN u-law compressed(G.721 ADPCM) +0010h 1 dword Sampling rate +0014h 1 dword Number of sample channels +EXTENSION:AU +OCCURENCES:SunOS +--------B-BGI-G----------------------------- +The BGI files are graphic drivers used by the Borland compilers to +provide graphics output for different graphics cards. They are loaded +dynamically. The exact format is not known to me ... +OFFSET Count TYPE Description +0000h 4 char ID='FBGD' +0004h 1 dword ID=08080808h + used to backspace over ID if typing the file +0008h ? char Driver ID string, terminated with #26 +EXTENSION:BGI +OCCURENCES:PC +PROGRAMS:Borland Pascal, Borland C, Turbo Pascal +--------I-BMP------------------------------- +The BMP files are the way, Windows stores bit mapped images. The BMP image +data is bit packed but every line must end on a dword boundary - if thats not +the case, it must be padded with zeroes. BMP files are stored bottom-up, +that means that the first scan line is the bottom line. The BMP format has four +incarnations, two under Windows (new and old) and two under OS/2, all are +described here. +OFFSET Count TYPE Description +0000h 2 char ID='BM' - BitMap + OS/2 also supports the following IDs : + ID='BA' - Bitmap Array + ID='CI' - Color Icon + ID='CP' - Color Pointer (mouse cursor) + ID='IC' - Icon + ID='PT' - Pointer (mouse cursor) +0002h 1 dword Filesize of whole file +0006h 4 byte reserved +000Ah 1 dword Offset of bitmap in file + ="BOF" +000Eh 1 dword Length of BitMapInfoHeader + The BitMapInfoHeader starts directly after + this header. + 12 - OS/2 1.x format + 40 - Windows 3.x format + 64 - OS/2 2.x format +0012h 1 dword Horizontal width of bitmap in pixels +0016h 1 dword Vertical width of bitmap in pixels +001Ah 1 word Number of planes +001Ch 1 word Bits per pixel ( thus the number of colors ) + ="BPP" +001Eh 1 dword Compression type, see ALGRTHMS.txt for descrip- + tion of the different types + 0 - none + 1 - RLE 8-bit/Pixel + 2 - RLE 4-bit/Pixel +0022h 1 dword Size of picture in bytes +0026h 1 dword Horizontal resolution +002Ah 1 dword Vertical resolution +002Ah 1 dword Number of used colors +002Ah 1 dword Number of important colors +0036h ? rec Definition of N colors + N=1 shl "BPP" + 1 byte Blue component + 1 byte Green component + 1 byte Red component + 1 byte Filler +"BOF" ? byte Image data +EXTENSION:BMP,RLE,LGO +OCCURENCES:PC +PROGRAMS:Windows,Paintbrush +REFERENCE:DDJ0994 +VALIDATION: +SEE ALSO:rDIB +--------I-CEG------------------------------- +The CEG (Continous Edge Graphic)-format is a raw picture format used by the +Edsun cards with CEG-chips which provide some better look through anti-aliasing +or something like that. The header before the data looks like this : + +OFFSET Count TYPE Description +0000h 1 word Version number of the CEG-format +0002h 9 char ID='Edsun CEG' +000Bh 1 byte Number of pixels per byte +000Ch 9 byte Reserved +0015h 80 char ASCIIZ copyright notice for the image +0065h 1 byte CEG-revision number (1) +0066h 1 byte Used CEG-mode (0..15) +0067h 1 Word Number of pixels per line +0069h 1 word Number of lines +006Ah 1 byte Old VGA-mode +006Bh 1 byte VGA Data flag : + 0 - VGA registers are invalid + 1 - VGA registers are valid +006Ch 92 byte VGA register data +00C2h 256 rec VGA palette entries + 1 byte Value for red + 1 byte Value for green + 1 byte Value for blue +03C2h 1 word Year of file creation +03C4h 1 byte Day of file creation +03C5h 1 byte Month of file creation +03C6h 1 byte Hour of file creation +03C7h 1 byte Minute of file creation +03C8h 1 byte Second of file creation +03C9h 24 byte Reserved for future use +EXTENSION:??? +OCCURENCES:PC +PROGRAMS:??? +--------a-CEL------------------------------- +CEL files contain one or more frames of image data used by the Autodesk +Animator and Animator Pro animation pakages. Both Animator Pro and the original +Animator produce CEL files, but each uses a different file format. + +--- Animator Pro CEL Files + +An Animator Pro CEL file is identical to a FLC file in all respects. A CEL file +should have a Celdata block in the file prefix block which describes the x,y +placement of the CEL. If the Celdata placement block is not present, assume a +placement of 0,0. + +--- Original Animator CEL Files + +The original Animator also produced CEL files. These were still-picture files, +not the multi-frame files Animator Pro now uses. A CEL file from the original +Animator is identical to a PIC file from the original Animator in all respects. + +EXTENSION:CEL +OCCURENCES:PC +PROGRAMS:Autodesk Animator +SEE ALSO:FLIc,FLC,PIC +VALIDATION: +--------F-CHR------------------------------- +The CHR files are scalable fonts used by the Borland graphics interface +(BGI) to display fonts in graphics mode. +OFFSET Count TYPE Description +0000h 4 char ID='PK',08,08 +0004h 4 char ID='BGI ' +0008h ? char Font description, terminated with #26 +0008h 1 word Headersize ++???? ="SIZ" + 4 char Internal font name + 1 word Font file size in bytes + 1 byte Font driver major version + 1 byte Font driver minor version + 1 word 0100h + "SIZ" word Zeroes to pad out the header +0080h 1 char Signature byte, '+' means stroke font +0081h 1 word Number of chars in font file + ="NUM" +0083h 1 byte undefined +0084h 1 byte ASCII value of first char in file +0085h 1 word Offset to stroke definitions +0087h 1 byte Scan flag ?? +0088h 1 byte Distance from origin to top of capital +0089h 1 byte Distance from origin to baseline +008Ah 1 byte Distance from origin to bottom descender +008Bh 4 char Four character name of font +0090h "NUM" word Offsets to character definitions +0090h+ "NUM" byte Width table for the characters +"NUM"*2 +0090h+ Start of character definitions +"NUM"*3 + +The individual character definitions consist of a variable number of words +describing the operations required to render a character. Each word +consists of an (x,y) coordinate pair and a two-bit opcode, encoded as shown +here: + +Byte 1 7 6 5 4 3 2 1 0 bit # + op1 + +Byte 2 7 6 5 4 3 2 1 0 bit # + op2 + + Opcodes + + op1=0 op2=0 End of character definition. + op1=0 op2=1 Do scan + op1=1 op2=0 Move the pointer to (x,y) + op1=1 op2=1 Draw from current pointer to (x,y) + +EXTENSION:CHR +OCCURENCES:PC +PROGRAMS:Borland Pascal, Borland C +REFERENCE:BGIKIT.ZIP +SEE ALSO: +VALIDATION: +--------M-CMF-G----------------------------- +The CMF files are music files used by the SoundBlaster sound card family. The +Creative Labs Music Format might be proprietary, the info is guesswork. +OFFSET Count TYPE Description +0000h 4 char ID="CTMF" +********* +EXTENSION:CMF +OCCURENCES:PC +PROGRAMS:PLAYCMF.EXE +--------I-COL------------------------------- +A COL file stores the rgb values for entries in the color palette. Both +Animator Pro and the original Animator produce COL files, but the formats +are different. To process a COL file for input, check the file size. If it is +exactly 768 bytes, the file is an original Animator COL file. If the file is +any other size, it is an Animator Pro COL file - which makes identification +almost impossible. + +Animator Pro COL Files do have a 8-byte header : + +OFFSET Count TYPE Description +0000h 1 dword File size, including this header +0004h 1 word ID=0B123h +0006h 1 word Version, currently 0 + +Following the file header are palette entries in rgbrgb... order. Each of +the r, g, and b components is a single byte in the range of 0-255. Generally, +there will be data for 256 palette entries, but this cannot be assumed. +The actual number of palette entries is ((size-8)/3); if this value is not +an even multiple of three, the file is corrupted. + +Original Animator COL Files + +A COL file created by the original Animator is exactly 768 bytes +long. There is no file header or other control information in +the file. + +EXTENSION:COL +OCCURENCES:PC +PROGRAMS:Autodesk Animator, Autodesk Animator Pro +SEE ALSO:FLIc,FLT +--------E-COM------------------------------- +The COM files are raw binary executables and are a leftover from the old CP/M +machines with 64K RAM. A COM program can only have a size of less than one +segment (64K), including code and static data since no fixups for segment +relocation or anything else is included. One method to check for a COM file is +to check if the first byte in the file could be a valid jump or call opcode, but +this is a very weak test since a COM file is not required to start with a jump +or a call. In principle, a COM file is just loaded at offset 100h in the segment +and then executed. + +OFFSET Count TYPE Description +0000h 1 byte ID=0E9h + ID=0EBh + Those are not safe ways to determine wether a + file is a COM file or not, but most COM files + start with a jump. +Further information not available. +EXTENSION:COM +OCCURENCES:PC +SEE ALSO:EXE,MZ EXE,NE EXE +--------E-CORE-G---------------------------- +The core images are dumps of the system core from different unix machines (as +far as I gather). Info comes from a magic file - so this is only good for +identification. What you would do with a core image on a foreign machine, eludes +me anyway. Maybe the information below is wrong and the 386 core dump also +belongs to the word at 0174h... +OFFSET Count TYPE Description +0000h 4 char ID='core' +0174h 1 word Executable type 1 + 015Dh - B370 executable + 5D01h - B370 executable + 0158h - B370 executable + 5801h - B370 executable + 015Fh - XA370 executable + 05F01h - XA370 executable + 015Ah - XA370 executable +0176h 1 word Executable type 2 + 0176h - 386 executable + +EXTENSION:??? +OCCURENCES:Unix flavours +PROGRAMS:N/A +SEE ALSO: +--------D-CPI-G----------------------------- +The DOS CPI files are data files which are loaded by the country drivers of +MS-DOS. The information comes from a magic file, which makes it good for +identification only. +OFFSET Count TYPE Description +0000h 9 char ID=255,'FONT ',0 +EXTENSION:CPI +OCCURENCES:PC +PROGRAMS:MS-DOS +--------X-CRD-G----------------------------- +The Windows 3.1 Cardfile.EXE is a (simple) addressbook application included +with the Windows 3.1+ operating system by Microsoft. + +OFFSET Count TYPE Description + +EXTENSION:CRD +OCCURENCES:PC, ALPHA? +PROGRAMS:CARDFILE.EXE +--------X-DBase II-O------------------------ +The DBase II file format. +The dBASE II file header has a fixed size of 521 bytes. +OFFSET Count TYPE Description +0000h 1 byte dBASE version, 02h = dBASE II +0001h 1 word Number of data records in file + ="NDR" +0003h 1 byte Month of last update +0004h 1 byte Day of last update +0005h 1 byte Year of last update +0006h 1 word Size of each data record + ="DRS" +0008h 64 rec Field descriptors + 11 char ASCIIZ field name, 0Dh as first + char indicates end of list. + 1 char Data type + 'C' - Char + 'N' - Numerical + 'L' - Logical + 1 byte Field length + 1 word Field data address ( set in RAM ) + 1 byte Number of decimal places +0208h 1 byte If 0Dh, then all 32 field descriptors were used; + otherwise 00h +EXTENSION:DBF +OCCURENCES:PC +PROGRAMS:DBase +SEE ALSO:DBASE III,XBase +VALIDATION:FileSize="NDR"*"DRS"+0208h +--------X-DBase III------------------------- + DBASE - File header structure (DBASE III) +OFFSET Count TYPE Description +0000h 1 byte dBASE version, + 03h = dBASE III w/o *.DBT + 83h = dBASE III w *.DBT +0001h 1 byte Month of last update +0002h 1 byte Day of last update +0003h 1 byte Year of last update +0004h 1 dword Number of data records in file + ="NDR" +0008h 1 word Header size + ="HSZ" +000Ah 1 word Data record size + ="DRS" +000Ch 12 byte reserved +0020h ? rec Field descriptors + The list of field descriptors is + terminated with a terminator + byte 0Dh. + 11 char ASCIIZ field name + 1 char Data type + 'C' - Char + 'D' - Date + 'L' - Logical + 'M' - Memo + 'N' - Numerical + 1 dword Field data address ( set in RAM ) + 1 byte Field length + 1 byte Number of decimal places + 14 byte reserved +EXTENSION:DBF +SEE ALSO:DBASE II,XBase +OCCURENCES:PC +PROGRAMS:DBase +VALIDATION:FileSize="NDR"*"DRS"+"HSZ" +--------X-DBASE IV-------------------------- +**** Description missing **** +EXTENSION:DBF,DBT +OCCURENCES:PC +PROGRAMS:DBase 4.0, Clipper +REFERENCE: +SEE ALSO:DBASE II,DBASE III,XBase +VALIDATION: +--------M-DCM------------------------------- +The DCM module format was designed by Winfried Welti, and is based on a +RIFF / IFF style format called WUFF - Welti's Universal File header Format. + +The header for WUFF files is built much like the RIFF header : + +OFFSET Count TYPE Description +0000h 4 char ID="WUFF" +0004h 4 char Subformat ID, see below +0008h 1 dword File length including the WUFF header +000Ch 1 word File format version as BCD. + Bits 15-12 are flags : + 12 - Archive file. If set, the data after the + header contains only WUFF style files. + 13-15 - reserved. +000Eh 1 word Length of subheader following this header. + +The DCM format has a header ID of "DCMw" and a version word of 0100h. It extends +the header with the following values: + +0010h 1 word Song flags, bitmapped + 0 - Samples present + 1 - Songdata present + 2 - Infotext present + 3-15 - reserved +0012h 1 word Number of instruments + +After the header, there follow the included (WUFF) files; Allowed fileformats +for include are : MDCw (Patterns), EDIw (Instrument), TXTw (Text); see below. + +The MDC format is a module format which uses compiled pattern data. It has the +subformat ID "MDCw", the current version is 1.01, it extends the header with +the following fields : + +OFFSET Count TYPE Description +0010h 1 word Flags for the song (see table 0011) +0012h 1 word Internal frequency for replay +0014h 1 dword Length of packed data channels +0028h 1 byte Number of used channels + 24 : Chnls : Byte Used Channels (0..chnls-1) + +(Table 0011) +MDC song flags + 0 - Stereo enable + 1 - Free Frequency (can replay freq change in song ?) + 2-3 - Offset size : + 00 - Byte (mod offsets, multiply by 256) + 01 - Word (16 bit offsets) + 10 - DWord (32 bit offsets) + 11 - reserved + 4-5 - Panning range + 00 - GUS panning (4 bit, byte value) + 01 - 8 Bit panning + 10 - reserved + 11 - reserved + 6-7 - Instrument number range + 00 - Byte + 01 - Word + 10 - reserved + 11 - reserved + 8 - S3M compatibility bit (all ranges are like s3m : mod offsets, + GUS panning, Ins Num Range : Byte) + 9 - Tuning control + 0 - Use Period values (word) (s3m) + 1 - Use Frequency values (Dword) +10-15- reserved + +After the header, there comes the packed data for the module. This format +consists of one control byte and depending on the value some other data +bytes. + +Values of control byte : + 0 - Next Frame + 1 - End of File + 2 - Order Num. follows [byte] + 3 - Loop to Ord Num (1 byte follows) + 4 - Frames to wait follows [byte] + 5 - New Replay freq follows [byte] + 6..31 - reserved + +If the byte is greater than 31 then it has the following bitmapped format : + + 0-4 - Channel Nr. + 5 - Key Byte follows + 6 - Period Value follows [word] + 7 - Volume Value follows [byte] + +Key byte format, bitmapped : + + 0 - Start Sample + 1 - Stop Sample + 2 - Instr Nr follows [byte/word/??] + 3 - Offset follows [byte/word/??] + 4 - Pan pos follows [byte/??] + 5-7 - reserved + +The EDI format has an ID value of "EDIw" and a version of 0100h, and it extends +the header with the following information : + +OFFSET Count TYPE Description +0010h 1 word Sample flags, bitmapped + 0-1 - Loop type + 00 - none + 01 - forward loop + 10 - bidirectional loop + 11 - reserved + 2 - 32 bit values for sample length etc., see below + 3 - Sample is 16 bit + 4 - Frequency is 32 bit. + 5-15 - reserved +0012h 1 word C2 frequency of sample +0014h 1 dword Loop start, this may be a word, depending on + the sample flags. +0018h 1 dword Loop end, see loop start +001Ch 1 dword Sample length + +The song text is plain ASCII. +EXTENSION:DCM +OCCURENCES:PC +SEE ALSO:S3M +--------M-DMF------------------------------- +The Digital Music Files are high quality MOD style files with up to +32 channels/1024 beats per track. The X-Tracker by the demo group +D-Lusion produces this format. In general, the format is well organised +due to the ID/Blocklength structure wich makes downward compatibility to +older version files easy, but the Version 4 (current version) of the file +format, produced by X-Tracker 0.30á still requires some manual scanning for +the next ID which I regard as not so nice. Version 5 of the format has the +[SEQU] block length fixed, but the [SMPD] block has the length 0. + +The file consists of several blocks, each with a 4 char (dwordint) ID tag +and a length of the record data. The main file header looks as follows : +OFFSET Count TYPE Description +0000h 4 char ID='DDMF' +0004h 1 byte Version id. + 4 -> XTracker 0.30á +0005h 8 char Tracker name, e.g. 'XTRACKER', 'HACKTRAK' :-) +000Dh 30 char Song name (ASCIIZ?) +002Bh 20 char Name of composer (ASCIIZ?) +0049h 1 byte Day of creation +004Ah 1 byte Month of creation +004Bh 1 byte Year of creation + +The other headers have the standard skip record format, in this section +named DMFblock. The offsets start _after_ this header record : +OFFSET Count TYPE Description +0000h 4 char Record tag (see below) +0004h 1 dword Size of data bedwording to this tag + +DMFblock [INFO] + Contains some message in ASCII. Length of the message is the size of + the record. + +DMFblock [CMSG] + Contains the message the composer wants to bring to us. After the ID + record, another fill byte preceeds the real message ! +OFFSET Count TYPE Description +0000h 1 byte Junk byte +0001h ? char Composer message + +DMFblock [SEQU] + Contains the information necessary for sequencing the different tracks. +OFFSET Count TYPE Description +0000h 1 word Song loop start +0002h 1 word Song loop end +0004h ? word Sequencer data + +DMFblock [PATT] + This block contains the information about the different patterns and tracks. +0000h 1 word Maximum pattern (=Songlength) + ="MPT" +0004h 1 byte Number of channels of this song (<= 16) +0005h "MPT" rec Pattern data. + 1 byte Track entries. (<=32) + ="TET" + How many tracks this pattern has. + XTracker allows a different number of + tracks for each pattern. + 1 byte Beat information + High nibble : Ticks per beat + Low nibble : Beats per measure + 1 word Maximum number of ticks (<=512) + 1 dword Number of bytes to skip for the + next pattern information. + ? rec Track data stream + 1 byte Global track effect + 1 byte Global track data (only if global + effect >0 !!!) + "TET" rec + 1 byte Information byte, bitmapped + For each bit set in the info byte, one + or two data byte(s) follow. This info byte + must not always be there, see below. For + effects, 2 bytes follow. + 0 - reserved + 1 - Volume effect + 2 - Note effect + 3 - Instrument effect + 4 - Volume set + 5 - Note set + 6 - Instrument set + 7 - Counter to next information byte. + Not set means, that next info byte + follows in 1 tick, unit is in + ticks. + The maximum number of effects is 3 at a time, + the maxximum size of a track information is + 11 bytes (with info=0FEh). + ? rec Effect bytes + 1 byte Effect number + 1 byte Effect data + ? byte Set data +** Here follows the pattern data, but it's too late today ** + +DMFblock [INST] + This block contains the information about the instrument data. + If this block does not exists, then the instrument numbers in the patterns + point directly to the samples in the [SMPI] block. +OFFSET Count TYPE Description +0000h 1 byte Number of instruments +0001h ? rec Instrument information block + 30 char The name of the instrument + 1 byte Instrument type, bitmapped + 0 - Instrument type + 1 - Instrument type + 00 - Sample in [SMPI] block + 01 - MIDI device + 10 - FM instrument + 11 - reserved + 2 - valid attack envelope + 3 - sustain on + 4 - reserved + 5 - reserved + 6 - reserved + 7 - reserved + 1 byte Range entries + ="REN" + Like the GF1 patterns, an instrument can + consist of several samples. + "REN" rec Range definition + 1 byte Sample to be played in this range + 1 byte Length of this range in half tone steps up + 6 byte Not yet defined 6-point envelope + +DMFblock [SMPI] +This block contains the information about the samples stored in the file. +OFFSET Count TYPE Description +0000h 1 byte Number of samples (<= 250) + ="NUM" + "NUM" rec Sample record + 1 byte Length of sample name + ? char Name of the sample + 1 dword Length of sample in bytes + 1 dword Start of sample loop + 1 dword End of sample loop + 1 word Frequency used for C-3 + 1 byte Volume for sample + 0 - Don't change current volume + otherwise volume (linear scale) + 1 byte Sample type, bitmapped + 0 - not looped/looped + 1 - 8/16-bit sample + (16-bit not supported with X-Tracker v0.30) + 2,3 - Pack type : + 00 - unpacked, signed sample + 01 - pack type 0 + 10 - pack type 1 + 11 - pack type 2 + 4-6 - reserved, set to zero + 7 - Sample stored in dmf/bib + 1 word reserved, set to zero + 1 dword crc32 of sample to identify samples + in BIB. + +DMFblock [SMPD] +This block contains the sample data (raw or packed, see [SMPI] block) in the +following format : + etc. +OFFSET Count TYPE Description +0000h 1 dword Length of the following sample + ? byte Sample data (might be packed) + +DMFBlock [ENDE] +This block serves as a end of file marker and can be used for validation. +Note that the four ID characters are _not_ followed by a length dword ! Each DMF +file simply ends with the four characters 'ENDE'. +EXTENSION:DMF +OCCURENCES:PC +PROGRAMS:X-TRACKER,PLAY_DMF +SEE ALSO: +VALIDATION: +--------?-DMS------------------------------- +The DMS (Digital Music System??) are some other files I found on a +mixed system CD, so I include them in my listing. They are Amiga files, +so here's the call to the Amiga folks again. + +OFFSET Count TYPE Description +0000h 4 char ID="DMS!" +EXTENSION:DMS +OCCURENCES:Amiga +--------A-DWC-?----------------------------- +The DWC archives seem to be a relict from ancient computing times - I've never +seen any program that dealt with them or could create them. They are yet +included in this compilation for reasons I don't know. But maybe one of you +stumbles over such a file, he might find this documentation helpful. +The DWC archives consist of single file entries with one archive trailer. The +archive entries seem to be at the start of the archive, but maybe they are +stored at the end of the archive, before the trailer. Each file header has the +following format : + +OFFSET Count TYPE Description +0000h 13 char Name of the original file in ASCIIZ. +000Dh 1 dword Size of the original file +0011h 1 dword MS-DOS date and time of the original file +0015h 1 dword Size of the compressed file +0019h 1 dword Offset of compressed data in archive file +001Dh 3 byte reserved +0020h 1 byte Method : + 1 - crunched + 2 - stored + +The trailer at the end of each archive has the following format : +OFFSET Count TYPE Description +0000h 1 word Length of trailer (=27) +0002h 1 word Size of the directory entries (=34)?? +0004h 16 byte reserved +0014h 1 dword Count of the directory entries +0018h 3 char ID="DWC" + +EXTENSION:DWC?? +OCCURENCES:PC?? +PROGRAMS:DWC.EXE?? +--------S-EFE------------------------------- +The EFE files are instrument files for the Ensoniq sampler system. +Further information wanted. +EXTENSION:EFE +SEE ALSO:GKH,INS +--------E-EXE-X----------------------------- +Different types of executables have emerged on the Intel DOS related platforms - +but all contain at least a stub MZ Exe before their actual EXE body... +SEE ALSO:MZ EXE,NE EXE +--------M-FAR------------------------------- +The Fandarole composer is a 16 channel composer created by the group +Digital Infinity / Daniel Potter for digital music in module style. + +The Fandarole modules have the following format : +OFFSET Count TYPE Description +0000h 4 char ID='FAR',254 +0004h 40 char Song name +002Ch 3 char ID=13,10,26 + This ID makes it possible to see the song name + by simply typing the .far file. +002Fh 1 word Remaining header size +0031h 1 byte Version number as BCD, + high nibble = major version + low nibble = minor version +0032h 16 byte Channel on/off map + <> 0 means that channel is used +0042h 1 rec Editing data. + This data is not necessary for playback, + but is stored by the composer for resume of + edit. + 1 byte Current octave + 1 byte Current voice + 1 byte Current row + 1 byte Current pattern + 1 byte Current order + 1 byte Current sample + 1 byte Current volume + 1 byte Current top of screen display + 1 byte Current editing area + 0=samples, + 1=patterns, + 2=orders + 1 byte Current tempo (default tempo) +004Ch 16 byte Panning map for each channel, 0=left,15=right +005Ch 1 byte Marked block start +005Dh 1 byte Marked block end +005Eh 1 byte Grid granularity +005Fh 1 byte Edit mode +0060h 1 word Song text length + ="STL" +0062h "STL" char Song text +0062h+ 256 byte Order bytes for pattern ordering + "STL" +0162h+ 1 byte Number of stored patterns + "STL" +0163h+ 1 byte Song length in patterns + "STL" +0164h+ 1 byte Loop position. This is the restart position + "STL" if the end of the song is reached. +0165h+ 256 word Length of each pattern. The number of rows in + "STL" each pattern is ( this word-2 )/(16*4) + +After this block, there might be additional data in the future (see remaining +header size, above), after that, the pattern data follows. + +The pattern data : +OFFSET Count TYPE Description +0000h 1 byte Length of pattern in rows + ="LIR" +0001h 1 byte Tempo for this pattern - Unsupported, + use not recommended +0002h 4*"LIR" rec Note data for each pattern in 4 channels + 1 byte Note value (Octave*12+Note)+1 + 0 means no note + 1 byte Sample number + 1 byte Volume byte. The volume is stored reversed, + the lower nibble is the major volume, the lower + nibble is the minor volume adjust. + 1 byte Effect byte. Upper nibble is effect, lower + nibble is data. (see table 0004) + +(Table 0004) +Note Effects in FAR-modules + 01 - Pitch adjust + 02 - Pitch adjust + 03 - Portamento to note + 04 - Retrigger note data times for one bar + 05 - Set vibrato depth + 06 - Vibrato + 07-0C - ?Possibly undefined? + 0D - Fine tune tempo down 128/Tempo + 0E - Fine tune tempo up 128/Tempo + 0F - Tempo, notes per second = 32/Tempo + +After the pattern data, the sample map follows. This is an array of 64 bits +(eight bytes), each set bit corresponds to a sample record stored in the file, +each zero bit means that the corresponding record is not stored in the file. + +OFFSET Count TYPE Description +0000h 8 byte Sample flags, see above + +After the sample flags, the samples themselves are stored in the FSM format, +except for the ("FSM",254) header. They follow header-data-header-data-etc., +see the FSM entry for further information. + +EXTENSION:FAR +OCCURENCES:PC +PROGRAMS:Fandarole Composer +REFERENCE: +SEE ALSO:FSM +VALIDATION: +--------a-FLT------------------------------- +The FLC files are files created by the Autodesk Animator Pro and contain +animations. The FLC files are a superset of those created by the Autodesk +Animator (FLIc files). In some cases, new data fields or compression methods +were added. The FLC files use a hierarchical block oriented structure and blocks +are a combination of control information and data. The file consists of one +header followed by data blocks. It is possible that new types of blocks not +described in this document will be added to animation files in the future. It is +recommended that you quietly ignore unknown block types you encounter during +animation playback. The size fields in the block headers make it easy to skip +an entire unrecognized block. + +The FLC files consist of one 128-byte header block and one or more of the +following blocks : + +The prefix block, if present, contains Animator Pro settings information, +CEL placement information, and other auxiliary data. + +A frame block exists for each frame in the animation. In addition, a ring frame +follows all the animation frames. Each frame block contains color palette +information and/or pixel data. + +The ring frame contains delta-compressed information to loop from the last frame +of the flic back to the first. It can be helpful to think of the ring frame as a +copy of the first frame, compressed in a different way. All flic files will +contain a ring frame, including a single-frame flic. + +The FLC file header + +OFFSET Count TYPE Description +0000h 1 dword The size of the whole animation file, including + the size of this header. +0004h 1 word ID=0AF12h +0006h 1 word Number of frames in this animation, not + including the ring frame. FLC files have a + maximum length of 4000 frames. +0008h 1 word Screen width in pixels +000Ah 1 word Screen height in pixels +000Ch 1 word Bits per pixel (always 8) +000Eh 1 word Flags - bitmapped + 0 - Ring frame not written / ring frame written + 1 - Flic header not updated / updated + 2-15 - reserved +0010h 1 dword Delay between frames in miliseconds. +0014h 1 word reserved +0016h 1 dword MS-DOS date and time of file creation (see table 0009) +001Ah 1 dword Serial number of the Animator Pro program used + to create the file. If the file was created + with the FlicLib development kit, this value + equals 0464c4942h ("FLIB"). +001Eh 1 dword MS-DOS date and time of last modification (see table 0009) +0022h 1 dword Serial number of program that made the last + modification. See Serial Number. +0026h 1 word X-axis aspect ratio of the file +0028h 1 word Y-axis aspect ratio of the file + (320x200 = 6:5) +002Ah 38 byte reserved (0) +0050h 1 dword Offset from begin of file to the first + animation frame block. +0054h 1 dword Offset from begin of file to the second + animation frame block. This value is used + when looping the animation. +0058h 40 byte reserved (0) + +Each subblock in the animation file has an identical header structure, +which is formatted like this : +0000h 1 dword The size of the whole block and all subordinate + blocks including the size of this header +0004h 1 word Block ID, varies depending on the block type. +0006h 1 word Number of subordinate blocks in this block. + including the ring frame. FLC files have a + maximum length of 4000 frames. +0008h 8 byte reserved(0) + +Immediately after the header there may be an optional prefix block, which is +used to store additional data which is not directly involved in animation +playback. + +The prefix block has the usual header with an ID of 0F100h. +The prefix block should only be created by the Animator Pro programs and never +by any other software, it is to be ignored by other software. + +The FLC frame blocks contain the information to convert the current frame into +the next frame; they have an ID of 0F1FAh. Directly after the frame header, +there are the subordinate data blocks - if the subblock count is 0 this means, +that the current frame is identical to the previous frame, only the appropriate +delay has to be made. +The data blocks have a different header format : +OFFSET Count TYPE Description +0000h 1 dword Size of this block, including header size +0004h 1 word Data type identifier : + 4 - 256-level color palette info + 7 - Word-oriented delta compression + 11 - 64-level color palette info + 12 - Byte-oriented delta compression + 13 - Entire frame is color index 0 + 15 - Byte run length compression + 16 - No compression + 18 - Postage stamp sized image +0006h ? byte Color or pixel data + +The following sections describe each of these data encoding methods in detail. + +--- Block Type 4 (FLI_COLOR256) - 256-Level Color + +The data in this block is organized in packets. The first word following the +block header is a count of the number of packets in the blocks. Each packet +consists of a one-byte color index skip count, a one-byte color count and three +bytes of color information for each color defined. + +At the start of the block, the color index is assumed to be zero. Before +processing any colors in a packet, the color index skip count is added to the +current color index. The number of colors defined in the packet is retrieved. +A zero in this byte indicates 256 colors follow. The three bytes for each color +define the red, green, and blue components of the color in that order. Each +component can range from 0 (off) to 255 (full on). The data to change colors +2,7,8, and 9 would appear as follows: + + 2 ; two packets + 2,1,r,g,b ; skip 2, change 1 + 4,3,r,g,b,r,g,b,r,g,b ; skip 4, change 3 + +--- Block Type 11 (FLI_COLOR) - 64-Level Color + +This block is identical to FLI_COLOR256 except that the values for the red, +green and blue components are in the range of 0-63 instead of 0-255, i.e. in +native VGA values which can be written to the VGA without modification. + +--- Block Type 13 (FLI_BLACK) - No Data +This block has no data following the header. All pixels in the frame are set to +color index 0. + +--- Block Type 16 (FLI_COPY) - No Compression + +This block contains an uncompressed raw image of the frame, from upper left +to the lower right, storing each line sequentially. This type of block is +created when the preferred compression method (SS2 or BRUN) generates more +data than the uncompressed frame image; a relatively rare situation. + +--- Block Type 15 (FLI_BRUN) - Byte Run Length Compression + +This block contains the entire image in a compressed format. Usually this block +is used in the first frame of an animation, or within a postage stamp image +block. + +The data is organized in lines. Each line contains packets of compressed pixels. +The first line is at the top of the animation, followed by subsequent lines +moving downward. The number of lines in this block is given by the height of the +animation. + +The first byte of each line is a count of packets in the line. This value is +ignored, it is a holdover from the original Animator. It is possible to generate +more than 255 packets on a line. The width of the animation is now used to drive +the decoding of packets on a line; continue reading and processing packets until +width pixels have been processed, then proceed to the next line. + +Each packet consist of a type/size byte, followed by one or more pixels. If the +number is negative (the high bit of the packet type is set), the absolute value +is the count of pixels to be copied from the packet to the animation image, +otherwise the next byte contains a single pixel which is to be replicated; +The lower 7 bits are the number of times the pixel is to be replicated. + +--- Block Type 12 (FLI_LC) - Byte Aligned Delta Compression + +This block contains the differences between the previous frame and this frame. +This compression method was used by the original Animator, but is not created by +Animator Pro. This type of block can appear in an Animator Pro file, however, if +the file was originally created by Animator, then some (but not all) frames were +modified using Animator Pro. + +The first word following the block header contains the position of the first +line in the block. This is a count of lines (down from the top of the image) +which are unchanged from the prior frame. The second word contains the number of +lines in the block. The data for the lines follows these two words. + +Each line begins with two bytes. The first byte contains the starting x position +of the data on the line, and the second byte the number of packets for the line. +Unlike BRUN compression, the packet count is significant (because this +compression method is only used on 320x200 flics). + +Each packet consists of a single byte column skip, followed by a packet type/ +size byte, which has the reverse meaning of in the block type 15. + +--- Block Type 7 (FLI_SS2) - Word Aligned Delta Compression + +This format contains the differences between consecutive frames. This is the +format most often used by Animator Pro for frames other than the first frame of +an animation. It is similar to the line coded delta (LC) compression, but is +word oriented instead of byte oriented. The data is organized into lines and +each line is organized into packets. + +The first word in the data following the block header contains the number of +lines in the block. Each line can begin with some optional words that are used +to skip lines and set the last byte in the line for animations with odd widths. +These optional words are followed by a count of the packets in the line. The +line count does not include skipped lines. + +The high order two bits of the word is used to determine the contents of +the word : + + Bit 15 Bit 14 Meaning + + 0 0 The word contains the packet count. The packets follow + this word. The packet count can be zero; this occurs + when only the last pixel on a line changes. + + 1 0 The low order byte is to be stored in the last byte of + the current line. The packet count always follows this + word. + + 1 1 The word contains a line skip count. The number of + lines skipped is given by the absolute value of the + word. This word can be followed by more skip counts, + by a last byte word, or by the packet count. + +The packets in each line are similar to the packets for the line coded block. +The first byte of each packet is a column skip count. The second byte is a +packet type. If the packet type is positive, the packet type is a count of words +to be copied from the packet to the animation image. If the packet type is +negative, the packet contains one more word which is to be replicated. The +absolute value of the packet type gives the number of times the word is to be +replicated. The high and low order byte in the replicated word do not +necessarily have the same value. + +--- Block Type 18 (FLI_PSTAMP) - Postage Stamp Image + +This block type holds a postage stamp - a reduced-size image - of the frame. It +generally appears only in the first frame block within a flic file. When +creating a postage stamp, Animator Pro considers the ideal size to be 100x63 +pixels. The actual size will vary as needed to maintain the same aspect ratio as +the original. +The pixels in a postage stamp image are mapped into a six-cube color space, +regardless of the color palette settings for the full frame image. A six-cube +color space is formed as follows: + + start at palette entry 0 + for red = 0 thru 5 + for green = 0 thru 5 + for blue = 0 thru 5 + palette_red = (red * 256)/6 + palette_green = (green * 256)/6 + palette_blue = (blue * 256)/6 + move to next palette entry + end for blue + end for green + end for red + +Any arbitrary rgb value (where each component is in the range of 0-255) can be +mapped into the six-cube space using the formula: + + ((6*red)/256)*36 + ((6*green)/256)*6 + ((6*blue)/256) + +The full postage stamp block header is defined as follows: + +Offset Length Name Description +OFFSET Count TYPE Description +0000h 1 dword Size of this block, including header size +0004h 1 word ID=18 +0006h 1 word Height of the postage stamp image +0008h 1 word Width of the image +000Ah 1 word Color translation type : + 1 - six-cube color space + +Immediately following this header is the postage stamp data. The data is +formatted as a block with standard size/type header. The type will be one of: + + 15 FPS_BRUN Byte run length compression + 16 FPS_COPY No compression + 18 FPS_XLAT256 Six-cube color xlate table + +The FPS_BRUN and FPS_COPY types are identical to the FLI_BRUN and FLI_COPY +encoding methods described above. + +The FPS_XLAT256 type indicates that the block contains a 256-byte color +translation table instead of pixel data. To process this type of postage stamp, +read the pixel data for the full-sized frame image, and translate its pixels +into six-cube space using a lookup in the 256-byte color translation table. This +type of postage stamp appears when the size of the animation frames is smaller +than the standard 100x63 postage stamp size. +************* +TWE - Tween Data Files + +A TWE file holds information about a tweening operation set up +via the Tween menus. The information includes the starting and +ending shapes, and the optional userD specified links between the +shapes. Animator Pro creates tween files. + +A TWE file begins with an 8-byte header defined as follows: + +Offset Length Name Description + + 0 2 magic File format identifier. Always hex 1995. + + 2 2 version The file format version; always zero. + + 4 4 tcount The number of tween shapes in the file; + always 2. + + 8 8 reserved Unused space; set to zeroes. + + 16 4 linkcount The number of link entries in the file. + +Immediately following the file header are the link entries. If +the linkcount value is zero there are no links. Each link entry +is a pair of 32-bit integers. The first value in each pair is the +index of the point in the first shape, and the second value is +the index of the point in the ending shape. (IE, a link value of +2,7 says to link the second starting-shape point to the seventh +ending-shape point.) + +Following the link entries is the data block that describes the +starting shape, then the data block that describes the ending +shape. The format of these blocks is identical to that of the +polygon (PLY) file, including file header data. In other words, +they appear as if a pair of polygon files are embedded in the +tween file at this point. + +********** +OPT - Optics Menu Settings Files + + +An OPT file holds information about an optics operation set up +via the Optics menus. Both Animator Pro and the original +Animator create OPT files. The file format is the same for both. + +An OPT file starts with a 4-byte header, as follows: + +Offset Length Name Description + + 0 2 magic File type identifier. Always hex 1A3F. + + 2 2 count Number of records in the file. + +Following the file header are optics records of 50 bytes each. A +record is generated for each click on CONTINUE MOVE in the OPTICS +menu. The move records are formatted as follows: + +Offset Length Name Description + + 0 4 link In the file, this field is always zero. + In memory, it's a pointer to the next + move record. + + 4 6 spincenter The x,y,z coordinates of the spin + center point; three 16-bit values. + + 10 6 spinaxis The x,y,z coordinates of the spin axis; + three 16-bit values. + + 16 6 spinturns The x,y,z coordinates of the spin turns; + three 16-bit values. + + 22 4 spininter Intermediate turns. Two 16-bit values. + These are values for a conjugation matrix + that corresponds to spin axis. + + 26 6 sizecenter The x,y,z coordinates of the size + center point; three 16-bit values. + + 32 2 xmultiplier Determines (along with xdivisor) + how to scale along x dimension. + + 34 2 xdivisor Determines (along with xmultiplier) how + to scale along x dimension. + + 36 2 ymultiplier Determines (along with ydivisor) + how to scale along y dimension. + + 38 2 ydivisor Determines (along with ymultiplier) how + to scale along y dimension. + + 40 2 bothmult Like xmultiplier, but applied to both + dimensions. + + 42 2 bothdiv Like xdivisor, but applied to both + dimensions. + + 44 6 linearmove The x,y,z offset for a linear move; + three 16-bit values. + +EXTENSION:FLT +OCCURENCES:PC +PROGRAMS:Autodesk Animator Pro +REFERENCE: +SEE ALSO:FLIc +VALIDATION: +--------a-FLIc------------------------------ +The Flic file format was one of the first graphic animation formats on the PC. +It was developed by <> and used by the Autodesk Animator. It provides relatively +fast animation in 320x200 resolution modes. The FLI use delta updating for +faster animation. The single block information and prefix blocks are missing for +the FLI files, see the FLT format for a discussion. + +OFFSET Count TYPE Description +0000h 1 dword Size of the FLIc file +0004h 1 word ID=0AF11h + AF11h means the file is a FLI file. +0006h 1 word Number of frames +0008h 1 word Width of displayed animation +000Ah 1 word Height of displayed animation +000Ch 1 word Number of used colors ("Depth") +000Eh 1 word Flags (=0003h) +0010h 1 dword Frame speed in sec/1024 ** +0014h 1 word reserved +0016h 1 dword Date/Time of creation in DOS format (see table 0009) +001Ah 1 dword Creator +001Eh 1 dword Date/Time of last change in DOS format (see table 0009) +0022h 1 dword Serial number? of changer +0026h 1 word X-Aspect ratio of animation +0028h 1 word Y-Aspect ratio of animation +002Ah 38 byte reserved +0052h 1 dword Offset of frame 1 in file +0056h 1 dword Offset of frame 2 in file +005Ah 40 byte reserved +EXTENSION:FLI,FLT +OCCURENCES:PC +REFERENCE:DDJ0693 +PROGRAMS:Autodesk Animator +SEE ALSO:QuickTime,AVI,FLT +--------D-FON-?----------------------------- +The Telix .FON files are the telephone books Telix uses to store numbers in. +The format is for Telix 3.22 + +OFFSET Count TYPE Description +0000h 1 dword ID=2E2B291Ah +0004h 1 word Version info (=1) +0006h 1 word Number of entries in directory (count from 1) +0007h 1 char ?will be used for encryption? + Currently 0 +0008h 55 byte reserved +0040h ? rec Actual phonebook entry + 25 char Name (0 terminated) + 17 char Phone number (0 terminated) + 1 byte Baud rate (see table 0006) + 1 byte Parity type (see table 0007) + 1 byte Data bits (7 or 8) + 1 byte Stop bits (1 or 2) + 12 char Script file name + 6 char Date of last call in ASCII + 1 word Number of total calls + 1 byte Terminal type (see table 0008) + 1 byte Protocol + 1 byte Flags, bitmapped + 0 - Local echo on / off + 1 - add linefeeds on / off + 2 - backspace is destructive on / off + 3 - backspace sends DEL / sends BS + 4 - strip high bits on / off + 5-7 - reserved + 1 word unknown + 1 byte Dial prefix index + 14 char Password + +(Table 0006) +Baud rate tables for Telix + + 0 = 300 baud + 1 = 1200 baud + 2 = 2400 baud + 3 = 4800 baud + 4 = 9600 baud + 5 = 19200 baud + 6 = 38400 baud + 7 = 57600 baud + 8 = 115200 baud + +(Table 0007) +Parity types for Telix + + 0 = None + 1 = Even + 2 = Odd + 3 = Mark + 4 = Space + +(Table 0008) +Terminal types for Telix + + 0 = TTY + 1 = ANSI-BBS + 2 = VT102 + 3 = VT52 + 4 = AVATAR + 5 = ANSI + +EXTENSION:FON +OCCURENCES:PC +PROGRAMS:Telix v3.22 +REFERENCE: +SEE ALSO: +VALIDATION: +--------M-FPT------------------------------- +The Fandarole Pattern files are used by the Fandarole Composer to store +single patterns in a file. + +OFFSET Count TYPE Description +0000h 4 char ID='FPT',254 +0004h 32 char ASCII pattern name +0024h 3 char ID=10,13,26 +0027h 1 word Remaining size of file (size of pattern) +0029h 1 byte Break location (length of pattern) +002Ah 1 byte reserved +002Bh ? byte Pattern in raw format like in the .FAR file +EXTENSION:FAR,FPT +OCCURENCES:PC +PROGRAMS:Fandarole Composer +SEE ALSO:FAR,FSM +VALIDATION: +--------S-FSM------------------------------- +The .FSM files are samples to be used for module style music with the +Fandarole Composer. Currently only samples of up to 64K length are supported, +altough the header reserves a dword for the sample size. +OFFSET Count TYPE Description +0000h 4 char ID='FSM',254 +0004h 32 char ASCII name of sample +0024h 3 char ID=10,13,26 +0027h 1 dword Length of sample (<=64K) +0028h 1 byte Fine tune value for sample + (currently unsupported) +0029h 1 byte Sample volume + (currently unsupported) +002Ah 1 dword Start of sample loop +002Dh 1 dword End of sample loop. If the sample is not set + to loop (see below) this should be set to the + end of the sample. +0032h 1 byte Sample type, bitmapped + 0 - 8-bit/16-bit sample + 1-7 - reserved +0033h 1 byte Loop mode, ?bit mapped? + 0-2 - reserved + 3 - loop off/loop on + 4-7 - reserved +0034h ? byte Sample data in signed format + +EXTENSION:FSM +OCCURENCES:PC +PROGRAMS:Fandarole Composer +REFERENCE: +SEE ALSO:FAR,USM +VALIDATION: +--------S-GF1 PATCH------------------------- +The GF1 Patch files are multipart sound files for the Gravis Ultrasound +sound card to emulate MIDI sounds in high quality. Each Patch can consist +of many samples (for example, a string ensemble consists of Violin, Viola, +Cello, Bass) which are played depending on the note to play. A patch can also +contain a part to be played before the loop and a part to be played after +the tone has been released. +OFFSET Count TYPE Description +0000h 12 char ID='GF1PATCH110' +000Ch 10 char Manufacturer ID +0018h 60 char Description of the contained Instruments + or copyright of manufacturer. +0054h 1 byte Number of instruments in this patch +0055h 1 byte Number of voices for sample +0056h 1 byte Number of output channels + (1=mono,2=stereo) +0057h 1 word Number of waveforms +0059h 1 word Master volume for all samples +005Bh 1 dword Size of the following data +0060h 36 byte reserved + +Following this header, the instruments with their headers follow. +An instrument header contains the name and other data about one +instrument contained within the patch. +OFFSET Count TYPE Description +0000h 1 word Instrument number. ?Maybe the MIDI instrument + number?. In the Gravis patches, this is 0, in + other patches, I found random values. +0002h 16 char ASCII name of the instrument. +0012h 1 dword Size of the whole instrument in bytes. +0016h 1 byte Layers. Needed for whatever. +0017h 40 byte reserved + +About the patch, I don't know anything. Maybe somebody could enlighten me. +Each patch record has the following format : +OFFSET Count TYPE Description +0000h 7 char Wave file name +0007h 1 byte Fractions +0008h 1 dword Wave size. + Size of the wave digital data +000Ch 1 dword Start of wave loop +0010h 1 dword End of wave loop +0012h 1 word Sample rate of the wave +0014h 1 word Minimum frequency to play the wave +0016h 1 word Maximum frequency to play the wave +0018h 1 dword Original sample rate of the wave data +001Ch 1 int Fine tune value for the wave +001Eh 1 byte Stereo balance, values unknown** +001Fh 6 byte Filter envelope rate +0025h 6 byte Filter envelope offse +002Bh 1 byte Tremolo sweep +002Ch 1 byte Tremolo rate +002Dh 1 byte Tremolo depth +002Fh 1 byte Vibrato sweep +0030h 1 byte Vibrato rate +0031h 1 byte Vibrato depth +0032h 1 byte Wave data, bitmapped + 0 - 8/16 bit wave data + 1 - signed/unsigned data + 2 - de/enable looping + 3 - no/has bidirectional looping + 4 - loop forward/backward + 5 - Turn envelope sustaining off/on + 6 - Dis/Enable filter envelope + 7 - reserved +0033h 1 int Frequency scale, whatever that means +0035h 1 word Frequency scale factor +0037h 36 byte Reserved + +EXTENSION:PAT +OCCURENCES:PC +PROGRAMS:Patch Maker +SEE ALSO:VOC,WAVe +--------I-GIF------------------------------- +The Graphics Interchange Format (tm) was created by Compuserve Inc. as a +standard for the storage and transmission of raster-based graphics information, +i.e. images. A GIF file may contain several images, which are to be displayed +overlapping and without any delay betwenn the images. The image data itself is +compressed using a LZW scheme. Please note that the LZW algorithm is patented by +UniSys and that since Jan. 1995 royalties to Compuserve are due for every software +that implements GIF images. +The GIF file consists of a global GIF header, one or more image blocks and +optionally some GIF extensions. + +OFFSET Count TYPE Description +0000h 6 char ID='GIF87a', ID='GIF89a' + This ID may be viewed as a version number +0006h 1 word Image width +0008h 1 word Image height +000Ah 1 byte bit mapped + 0-2 - bits per pixel -1 + 3 - reserved + 4-6 - bits of color resolution + 7 - Global color map follows image descriptor +000Bh 1 byte Color index of screen background +000Ch 1 byte reserved + +The global color map immediately follows the screen descriptor and has the size +(2**BitsPerPixel), and has the RGB colors for each color index. 0 is none, 255 +is full intensity. The bytes are stored in the following format : +OFFSET Count TYPE Description +0000h 1 byte Red component +0001h 1 byte Green component +0002h 1 byte Blue component + +After the first picture, there may be more pictures attached in the file +whic overlay the first picture or parts of the first picture. The Image +Descriptor defines the actual placement and extents of the following image +within the space defined in the Screen Descriptor. Each Image Descriptor is +introduced by an image separator character. The role of the Image Separator +is simply to provide a synchronization character to introduce an Image +Descriptor, the image separator is defined as ",", 02Ch, Any characters +encountered between the end of a previous image and the image separator +character are to be ignored. + +The format of the Image descriptor looks like this : +OFFSET Count TYPE Description +0000h 1 char Image separator + ID=',' +0001h 1 word Left offset of image +0003h 1 word Upper offset of image +0005h 1 word Width of image +0007h 1 word Height of image +0009h 1 byte Palette description - bitmapped + 0-2 - Number of bits per pixel-1 + 3-5 - reserved (0) + 6 - Interlaced / sequential image + 7 - local / global color map, ignore bits 0-2 + +To provide for some possibility of an extension of the GIF files, a special +extension block introducer can be added after the GIF data block. The block has +the following structure : + +OFFSET Count TYPE Description +0000h 1 char ID='!' +0001h 1 byte Extension ID +0002h ? rec + 1 word Byte count + ? byte Extra data +????h 1 byte Zero byte count - terminates extension block. + +EXTENSION:GIF +OCCURENCES:PC +PROGRAMS:CSHOW.EXE +SEE ALSO: +VALIDATION: +--------A-GZIP------------------------------ +The GNU ZIP program is an archive program mostly for the UNIX machines developed +by the GNU project. +OFFSET Count TYPE Description +0000h 2 char ID='!',139 +0002h 1 byte Method : + 0-7 - reserved + 8 - deflated +0003h 1 byte File flags : + 0 - ASCII-text + 1 - Multi-part file + 2 - Name present + 3 - Comment present + 4 - Encrypted + 5-8 - reserved +0004h 1 dword File date and time (see table 0009) +0008h 1 byte Extra flags +0009h 1 byte Target OS : + 0 - DOS + 1 - Amiga + 2 - VMS + 3 - Unix + 4 - ???? + 5 - Atari + 6 - OS/2 + 7 - MacOS + 10 - TOPS-20 + 11 - Win/32 +EXTENSION:ZIP +PROGRAMS:GNU gzip +--------S-GKH------------------------------- +The GKH files are disk images of the Ensoniq EPS sampler system. +Further information is missing. +EXTENSION:GKH +SEE ALSO:EFE,INS +--------a-GRASPRT GL-G---------------------- +The .GL animation files are graphic animations, some just .GIF files, others +mini-movies, used mostly for x-rated adult animations. The format of the files +is plain guesswork by me. The analyzed file did not include any animations but +only .GIF files and two text files which seemed to be the animation script. +There is no safe way of identifying a file as a GL animation, maybe except for +adding the subfile sizes and the header size and then check if this matches the +file size. +OFFSET Count TYPE Description +0000h 1 word Length of header, excluding this word + ="HLN" +0002h ? rec The directory entries for each file + 1 dword Offset of the stored file + 12 char DOS file name of the stored file +0002h+ 1 dword Length of the first stored file + "HLN" + ? byte The first file + The other files follow in similar + manner, length->file->length->file +EXTENSION:GL +OCCURENCES:PC +PROGRAMS:GRASPRT +--------?-GRIB------------------------------ +The GRIB weather product information files just might be some satellite images +or something else. I have only seen this signature in a magic file and further +informations about the format is not known to me. +OFFSET Count TYPE Description +0000h 4 char ID='GRIB' +EXTENSION:??? +OCCURENCES:??? +PROGRAMS:??? + +--------A-HA-------------------------------- +HA files (not to be confused with HamarSoft's HAP files [3]) contain a +small archive header with a word count of the number of files in the +archive. The constituent files stored sequentially with a header followed +by the compressed data, as is with most archives. + +The main file header is formatted as follows: +OFFSET Count TYPE Description +0000h 2 char ID='HA' +0002h 1 word Number of files in archive + +Every compressed file has a header before it, like this : + +OFFSET Count TYPE Description +0000h 1 byte Version & compression type +0001h 1 dword Compressed file size +0005h 1 dword Original file size +0009h 1 dword CCITT CRC-32 (same as ZModem/PkZIP) +000Dh 1 dword File time-stamp (Unix format) + ? ? char ASCIIZ pathname + ? ? char ASCIIZ filename +????h 1 byte Length of machine specific information + ? byte Machine specific information + +Note that the path separator for pathnames is the 0FFh (255) character. + +The high nybble of the version & compression type field contains the +version information (0=HA 0.98), the low nybble is the compression type : + +(Table 0012) +HA compression types + 0 "CPY" File is stored (no compression) + 1 "ASC" Default compression method, using a sliding + window dictionary with an arithmetic coder. + 2 "HSC" Compression using a "finite context [sic] + model and arithmetic coder" + 14 "DIR" Directory entry + 15 "SPECIAL" Used with HA 0.99B (?) + + +Machine specific information known: + + 1 byte Machine type (Host-OS) + + 1 = MS DOS + 2 = Linux (Unix) + + ? bytes Information (currently only file-attribute info) + +EXTENSION:HA +OCCURENCES:PC, Linux +PROGRAMS:HA +REFERENCE: +--------I-HSI1------------------------------ +The HSI1 images are a JPEG derivative made by Handmade Software for their +Image Alchemy package. +OFFSET Count TYPE Description +0000h 4 char ID='HSI1' +EXTENSION:JPG +OCCURENCES:PC,SUN +PROGRAMS:Image Alchemy +REFERENCE: +SEE ALSO:JPEG +VALIDATION: +--------A-HYP------------------------------- +The Hyper archiver is a very fast compression program by P. Sawatzki and K.P. +Nischke, which uses LZW compression techniques for compression. It is not very +widespread - in fact, I've yet to see a package distributed in this format. + +OFFSET Count TYPE Description +0000h 1 byte ID=1Ah +0001h 2 char Compression method + "HP" - compressed + "ST" - stored +0003h 1 byte Version file was compressed by in BCD +0004h 1 dword Compressed file size +0008h 1 dword Original file size +000Ch 1 dword MS-DOS date and time of file (see table 0009) +0010h 1 dword CRC-32 of file +0014h 1 byte MS-DOS file attribute +0015h 1 byte Length of filename + ="LEN" +0016h "LEN" char Filename + +EXTENSION:HYP +OCCURENCES:PC +PROGRAMS:HYPER.EXE +--------f-IFF-M----------------------------- +The IFF format is comparable to the RIFF file format, but it +uses Motorola byte ordering. After the FORM header, the different +records follow. Each record has a header ID of 4 bytes and then following +the size of the data (in Motorola byte ordering). Each IFF record starts on +an even byte boundary, that means if the record length is odd, you will have +to skip one more byte to get the next record. +OFFSET Count TYPE Description +0000h 4 char ID='FORM' +0004h 1 dword Size of the whole IFF block +0008h 4 char Type of the IFF file + +Each IFF record has the following format : +OFFSET Count TYPE Description +0000h 4 char ID +0004h 1 dword Blocksize +0008h ? byte Block data, depends on block type. + +OCCURENCES:Amiga,PC +SEE ALSO:8SVX,LBM,RIFF +--------S-INS------------------------------- +The INS files are instrument files for the Ensoniq sampler system. +Further information wanted. +EXTENSION:INS +SEE ALSO:EFE,GKH +--------I-JPEG-G---------------------------- +The JPEG image standard is a standard for lossy (but efficient) image +compression made by the ???? Group. The endianness of the JPEG files is unknown +to me, there seem to exist both types of JPEG files. + +The JPEG files are block oriented, there is a header for each JPG block, +but I was not able to find a list of all blocks - so you'll have to stick +with what I gathered here ;) + +Format of a JPEG block (all data is in Motorola byte order) : +OFFSET Count TYPE Description +0000h 1 word Block ID + 0FFD8h - JPEG signature block(4 chars="JFIF") + 0FFC0h - JPEG color information + 0FFC1h - JPEG color information +0002h 1 word Block size in bytes, without ID word. + +Format of JPEG color information (motorola byte order) : +OFFSET Count TYPE Description +0000h 1 byte 1=Grayscale image +0001h 1 word Height +0003h 1 word Width + +Another try for JPEG identification could be this one : +OFFSET Count TYPE Description +0000h 1 dword ID=FFD9FFE0h + ID=FFD8FFE0h + Big endian JPEG file (Intel) + ID=E0FFD8FFh + Little endian JPEG file (Motorola) + +EXTENSION:JPG +OCCURENCES:PC,Amiga,SUN +PROGRAMS: +REFERENCE: +SEE ALSO:HSI1 +VALIDATION: +--------I-LBM-M----------------------------- +The LBM/ILBM format is used by Deluxe Paint to store bitmap images. It +uses the IFF file format and Motorola byte order. +FORMblock [BMHD] +This block contains the information about the image. +OFFSET Count TYPE Description +0000h 1 word The image width (x-axis) +0002h 1 word The image height (y-axis) +0004h 1 dword reserved +0008h 1 byte Bits per pixel +0009h 1 byte ??reserved?? +FORMblock [BODY] +This block contains the (compressed) image data... **** +FORMblock [CRGN] +This block contains palette information for a range of palette entries. +OFFSET Count TYPE Description +FORMblock [TINY] +This block contains a small image used for previewing. +OFFSET Count TYPE Description +EXTENSION:IFF,LBM +OCCURENCES:AMIGA,PC +PROGRAMS:Deluxe Paint +REFERENCE:??? +SEE ALSO:IFF +--------A-LBR------------------------------- +The LBR files consist of a direcotry and one or more "members". The directory +contains from 4 to 256 entries and each entry describes one member. +The first directory entry describes the directory itself. All space allocations +are in terms of sectors, where a sector is 128 bytes long. Four directory +entries fit in one sector thus the number of directory entries is always evenly +divisible by 4. Different types of LBR files exist, all versions are discussed +here, the directory entry looks like this : + +OFFSET Count TYPE Description +0000h 1 byte File status : + 0 - active + 254 - deleted + 255 - free +0001h 11 char File name in FCB format (8/3, blank padded), + directory name is blanks for old LU, + ID='********DIR' + for LUPC +000Ch 1 word Offset to file data in sectors +000Eh 1 word Length of stored data in sectors + +For the LUPC program, the remaining 16 bytes are used like this : +OFFSET Count TYPE Description +0000h 8 char ASCII date of creation (MM/DD/YY) +0008h 8 char ASCII time of creation (HH:MM:SS) + +For the LU86 program, the remaining 16 bytes are used like this : +OFFSET Count TYPE Description +0000h 1 word CRC-16 or 0 +0002h 1 word Creation date in CP/M format +0004h 1 word Creation time in DOS format +0006h 1 word Date of last modification, CP/M format +0008h 1 word Time of last modification, DOS format +000Ah 1 byte Number of bytes in last sector +000Bh 5 byte reserved (0) + +EXTENSION:LBR +OCCURENCES:PC,CP/M +PROGRAMS:LU.COM, LUU.COM, LU86.COM +SEE ALSO: +--------A-LZH------------------------------- +The LHArc/LHA archiver is a multi platform archiver made by Haruyasu Yoshizaki, +which has a relatively good compression. It uses more or less the same +technology like the ZIP programs by Phil Katz. There was a hack named "ICE", +which had only the graphic characters displayed on decompression changed. + +OFFSET Count TYPE Description +0000h 1 byte Size of archived file header +0001h 1 byte Checksum of remaining bytes +0002h 3 char ID='-lh' + ID='-lz' +0005h 1 char Compression methods used (see table 0005) +0006h 1 char ID='-' +0007h 1 dword Compressed size +000Bh 1 dword Uncompressed size +000Fh 1 dword Original file date/time (see table 0009) +0013h 1 word File attribute +0015h 1 byte Filename / path length in bytes + ="LEN" +0016h "LEN" char Filename / path +0018h 1 word CRC-16 of original file ++"LEN" + +(Table 0005) +LHArc compression types + "0" - No compression + "1" - LZW, 4K buffer, Huffman for upper 6 bits of position + "2" - unknown + "3" - unknown + "4" - LZW, Arithmetic Encoding + "5" - LZW, Arithmetic Encoding + "s" - LHa 2.x archive? + "\" - LHa 2.x archive? + "d" - LHa 2.x archive? + +EXTENSION:LZH,ICE +OCCURENCES:PC +PROGRAMS:LHArc.EXE, LHA.EXE +--------M-MIDI-M---------------------------- +The MIDI file format is used to store MIDI song data on disk. The discussed +version of the MIDI file spec is the approved MIDI Manufacturers' Associations +format version 0.06 of (3/88). The contact address is listed in the adresses +file. Version 1.0 is technically identical but the description has been +rewritten. The description was made by Dave Oppenheim, most of the text was +taken right out of his document. + +MIDI files contain one or more MIDI streams, with time information for +each event. Song, sequence, and track structures, tempo and time signature +information, are all supported. Track names and other descriptive information +may be stored with the MIDI data. This format supports multiple tracks and +multiple sequences so that if the user of a program which supports multiple +tracks intends to move a file to another one, this format can allow that to +happen. + +The MIDI files are block oriented files, currently only 2 block types are +defined, header and track data. Opposed to the IFF and RIFF formats, no +global header is given, so that the validation must be done by adding the +different block sizes. + +A MIDI file always starts with a header block, and is followed by one or +more track block. + +The format of the header block : +OFFSET Count TYPE Description +0000h 4 char ID='MThd' +0004h 1 dword Length of header data (=6) +0008h 1 word Format specification + 0 - one, single multi-channel track + 1 - one or more simultaneous tracks + 2 - one or more sequentially independent + single-track patterns +000Ah 1 word Number of track blocks in the file +000Ch 1 int Unit of delta-time values. + If negative : + Absolute of high byte : + Number of frames per second. + Low byte : + Resolution within one frame + If positive, division of a quarter-note. + +The track data format : +The MTrk block type is where actual song data is stored. It is simply a +stream of MIDI events (and non-MIDI events), preceded by delta-time +values. + +Some numbers in MTrk blocks are represented in a form called a variable- +length quantity. These numbers are represented 7 bits per byte, most +significant bits first. All bytes except the last have bit 7 set, and +the last byte has bit 7 clear. If the number is between 0 and 127, it +is thus represented exactly as one byte. Since this explanation might not be +too clear, some exapmles : + + Number (hex) Representation (hex) + 00000000 00 + 00000040 40 + 0000007F 7F + 00000080 81 00 + 00002000 C0 00 + 00003FFF FF 7F + 001FFFFF FF FF 7F + 08000000 C0 80 80 00 + 0FFFFFFF FF FF FF 7F + +The largest number which is allowed is 0FFFFFFF so that the variable- +length representation must fit in 32 bits in a routine to write +variable-length numbers. + +Each track block contains one or more MIDI events, each event consists of +a delta-time and the number of the event. The delta-time is stored as a +variable-length quantity and represents the time to delay before the following +event. A delta-time of 0 means, that the event occurs simultaneous with the +previous event or occurs right at the start of a track. The delta-time unit is +specified in the header block. + +Format of track information block : +OFFSET Count TYPE Description +0000h 4 char ID='MTrk' +0004h 1 dword Length of header data +0008h ? rec , + +Three types of events are defined, MIDI event, system exclusive event and +meta event. The first event in a file must specify status; delta-time itself +is not an event. Meta events are non-MIDI informations. + +The format of the meta event : +OFFSET Count TYPE Description +0000h 1 byte ID=FFh +0001h 1 byte Type (<=128) +0002h ? ? Length of the data, 0 if no data + stored as variable length quantity + ? byte Data + +A few meta-events are defined. It is not required for every program to support +every meta-event. Meta-events initially defined include: + +FF 00 02 ssss Sequence Number +This optional event, which must occur at the beginning of a track, +before any nonzero delta-times, and before any transmittable MIDI +events, specifies the number of a sequence. + +FF 01 len text Text Event +Any amount of text describing anything. It is a good idea to put a text +event right at the beginning of a track, with the name of the track, a +description of its intended orchestration, and any other information +which the user wants to put there. Programs on a computer which does not +support non-ASCII characters should ignore those characters with the hi-bit +set. Meta event types 01 through 0F are reserved for various types of text +events, each of which meets the specification of text events(above) but is +used for a different purpose: + +FF 02 len text Copyright Notice +Contains a copyright notice as printable ASCII text. The notice should +contain the characters (C), the year of the copyright, and the owner of +the copyright. If several pieces of music are in the same MIDI file, +all of the copyright notices should be placed together in this event so +that it will be at the beginning of the file. This event should be the +first event in the first track block, at time 0. + +FF 03 len text Sequence/Track Name +If in a format 0 track, or the first track in a format 1 file, the name +of the sequence. Otherwise, the name of the track. + +FF 04 len text Instrument Name +A description of the type of instrumentation to be used in that track. + +FF 05 len text Lyric +A lyric to be sung. Generally, each syllable will be a separate lyric +event which begins at the event's time. + +FF 06 len text Marker +Normally in a format 0 track, or the first track in a format 1 file. +The name of that point in the sequence, such as a rehearsal letter or +section name ("First Verse", etc.). + +FF 07 len text Cue Point +A description of something happening on a film or video screen or stage +at that point in the musical score ("Car crashes into house", "curtain +opens", "she slaps his face", etc.) + +FF 2F 00 End of Track +This event is not optional. It is included so that an exact ending +point may be specified for the track, so that it has an exact length, +which is necessary for tracks which are looped or concatenated. + +FF 51 03 tttttt Set Tempo, in microseconds per MIDI quarter-note +This event indicates a tempo change. Another way of putting +"microseconds per quarter-note" is "24ths of a microsecond per MIDI +clock". Representing tempos as time per beat instead of beat per time +allows absolutely exact dword-term synchronization with a time-based sync +protocol such as SMPTE time code or MIDI time code. This amount of +accuracy provided by this tempo resolution allows a four-minute piece at +120 beats per minute to be accurate within 500 usec at the end of the +piece. Ideally, these events should only occur where MIDI clocks would +be located Q this convention is intended to guarantee, or at least +increase the likelihood, of compatibility with other synchronization +devices so that a time signature/tempo map stored in this format may +easily be transferred to another device. + +FF 54 05 hr mn se fr ff SMPTE Offset +This event, if present, designates the SMPTE time at which the track +block is supposed to start. It should be present at the beginning of +the track, that is, before any nonzero delta-times, and before any +transmittable MIDI events. The hour must be encoded with the SMPTE +format, just as it is in MIDI Time Code. In a format 1 file, the SMPTE +Offset must be stored with the tempo map, and has no meaning in any of +the other tracks. The ff field contains fractional frames, in 100ths of +a frame, even in SMPTE-based tracks which specify a different frame +subdivision for delta-times. + +FF 58 04 nn dd cc bb Time Signature +The time signature is expressed as four numbers. nn and dd represent +the numerator and denominator of the time signature as it would be +notated. The denominator is a negative power of two: 2 represents a +quarter-note, 3 represents an eighth-note, etc. The cc parameter +expresses the number of MIDI clocks in a metronome click. The bb +parameter expresses the number of notated 32nd-notes in a MIDI quarter- +note (24 MIDI Clocks). + +FF 59 02 sf mi Key Signature + sf = -7: 7 flats + sf = -1: 1 flat + sf = 0: key of C + sf = 1: 1 sharp + sf = 7: 7 sharps + + mi = 0: major key + mi = 1: minor key + +FF 7F len data Sequencer-Specific Meta-Event + Special requirements for particular sequencers may use this +event type: the first byte or bytes of data is a manufacturer ID. +However, as this is an interchange format, growth of the spec proper is +preferred to use of this event type. This type of event may be used by +a sequencer which elects to use this as its only file format; +sequencers with their established feature-specific formats should +probably stick to the standard features when using this format. + +The system exclusive event is used as an escape to specify arbitrary bytes +to be transmitted. The system exclusive event has two forms, to compensate +for some manufacturer-specific modes, the F7h event is used if a F0h is to +be transmitted. Each system exclusive event must end with an F7h event. +The format of a system exclusive event : +OFFSET Count TYPE Description +0000h 1 byte ID=F0h,ID=F7h +0001h ? ? Length as variable length qty. + ? byte bytes to be transmitted + +EXTENSION:MID,MIDI +OCCURENCES:PC,MAC +PROGRAMS:Cubase +VALIDATION: +--------M-MOD-M----------------------------- +The Protracker composer is a composer for digital music. The MOD files are a +quasi standard for digital music, all words are in Motorola byte order. The +original MOD format allowed only 4 digital channels and 15 instruments, the +specification became enlarged (maybe by Mahoney and Kaktus??) to 4 channels and +31 instruments. Check the file at offset 1080d for the signatures 'M.K', '4CHN', +'6CHN','8CHN','FLT4','FLT8. If you find any of them, the module uses 31 +instruments. With rising sound quality on the PC and other platforms, the old +MODule format has been replaced by numerous other formats. The 4/15 format has +almost become extinct. Below, only the 4/31 format is descripted. + +The digital sample data is signed (two's complement) as necessary for the Amiga, +the sample data immediately follows the pattern data. +Maybe this is not valid for some 8CHN files; One of the two I have, uses Intel +byte ordering and unsigned samples. + +OFFSET Count TYPE Description +0000h 20 char Song title, padded with spaces +0014h 31 rec Sample description record + For original MOD files, the number of + instruments would be 15. + 22 char Sample name, padded with zeroes to + full length. + 2 word Sample length / 2. Needs to be multiplied + by 2 to get the actual length. If the sample + length is greater than 8000h, the sample + is bigger than 64k. + 1 byte Sample finetune. Only the lower nibble is + valid. Fine tune table : + 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0 +1 +2 +3 +4 +5 +6 +7 -8 -7 -6 -5 -4 -3 -2 -1 + 1 byte Sample volume (0-40h) + 1 word Sample loop start / 2 + 1 word Sample loop length / 2 + +950d 1 byte Song length in patterns (0-80h) +951d 1 byte Restart byte for song looping (Noisetracker?) +952d 128 byte Pattern play sequences +1080d 4 char ID='M.K.', ID='4CHN',ID='6CHN',ID='8CHN' + ID='4FLT',ID='8FLT' + If this position contains 'M.K.','8CHN', + '4CHN','6CHN','FLT4' or 'FLT8' the module + has 31 instruments. +1084d ? rec Patterns + Each pattern has 64 rows. + Depending on the number of channels, each row + has from 4 to 8 notes. The channel count is + determined by the ID. (see table 0005) + The number of patterns is the highest pattern + number stored in the pattern list. + + Each note has four bytes. Four notes make + up a track in a four channel MOD file. Each + track is saved sequentially : + byte 0-3 4-7 8-11 12-15 + Chn #1 Chn #2 Chn #3 Chn #4 + byte 16-19 20-23 24-27 28-31 + Chn #1 Chn #2 Chn #3 Chn #4 + 1 word Instrument / period + The instrument number is in bits 12-15, the + 12-bit period in bits 0-11. + 1 byte Upper nibble : Lower 4 bits of the instrument, + Lower nibble : Special effect command. + 1 byte Special effects data +(Table 0005) +Protracker 16 note conversion table / MOD Period table + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ +PT16 : I 1I 2I 3I 4I 5I 6I 7I 8I 9I 10I 11I 12I +MOD : I 1712I 1616I 1524I 1440I 1356I 1280I 1208I 1140I 1076I 1016I 960I 906I +Note : I C-0I C#0I D-0I D#0I E-0I F-0I F#0I G-0I G#0I A-0I A#0I B-0I + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ + I 13I 14I 15I 16I 17I 18I 19I 20I 21I 22I 23I 24I + I 856I 808I 762I 720I 678I 640I 604I 570I 538I 508I 480I 453I + I C-1I C#1I D-1I D#1I E-1I F-1I F#1I G-1I G#1I A-1I A#1I B-1I + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ + I 25I 26I 27I 28I 29I 30I 31I 32I 33I 34I 35I 36I + I 428I 404I 381I 360I 339I 320I 302I 285I 269I 254I 240I 226I + I C-2I C#2I D-2I D#2I E-2I F-2I F#2I G-2I G#2I A-2I A#2I B-2I + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ + I 37I 38I 39I 40I 41I 42I 43I 44I 45I 46I 47I 48I + I 214I 202I 190I 180I 170I 160I 151I 143I 135I 127I 120I 113I + I C-3I C#3I D-3I D#3I E-3I F-3I F#3I G-3I G#3I A-3I A#3I B-3I + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ + I 49I 50I 51I 52I 53I 54I 55I 56I 57I 58I 59I 60I + I 107I 101I 95I 90I 85I 80I 75I 71I 67I 63I 60I 56I + I C-4I C#4I D-4I D#4I E-4I F-4I F#4I G-4I G#4I A-4I A#4I B-4I + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ + +EXTENSION:MOD,module +OCCURENCES:AMIGA,PC +PROGRAMS:DMP,ModEdit +VALIDATION:NONE +--------A-MS COMPRESS 5.0-G----------------- +Microsoft ships its files compressed with COMPRESS.EXE, for expansion the +program EXPAND.EXE (how original ;) ) is used. The program EXPAND.EXE is +available with every copy of MS-DOS 5.0+, the program COMPRESS.EXE is available +with several development kits, I found it with Borland Pascal 7.0. The +compression seems to be some kind of LZ-Compression, as the fully compatible? +LZCopy command under Windows can decompress the same files. This compression +feature seems to be available on all DOS-PCs. + +OFFSET Count TYPE Description +0000h 4 char ID='SZDD' +0004h 1 long reserved, always 3327F088h ? + +0008h 1 byte reserved +0009h 1 char Last char of filename if file was compressed + into "FILENAME.EX_". +000Ah 1 long Original file size +000Eh 1 byte reserved, varies... +EXTENSION:*.??_ +OCCURENCES:PC +PROGRAMS:COMPRESS.EXE, EXPAND.EXE, LZEXPAND.DLL +REFERENCE:?Windows SDK? +SEE ALSO:MS COMPRESS 6.22+ +VALIDATION: +--------A-MS COMPRESS 6.22+-G--------------- +At least with the version 6.22 of MS-DOS, Microsoft changed their compression +program to a new signature; The program seems no more to be able to restore +files to their original name, if it is not given on the command line. +OFFSET Count TYPE Description +0000h 4 char ID="KWAJ" +0004h 1 long reserved, always 0D127F088h ? +0008h 1 long reserved, always 00120003h ? +000Ch 1 word reserved, always 01 ? +EXTENSION:*.??_ +OCCURENCES:PC +PROGRAMS:COMPRESS.EXE, EXPAND.EXE, LZEXPAND.DLL +REFERENCE:?Windows SDK? +SEE ALSO:MS COMPRESS 5.0 +VALIDATION: +--------I-MSK------------------------------- +The MSK files are mask files used by the Autodesk Animator and Animator Pro +packages. Two types of MSK files exist. The Animator Pro version is simply a PIC +file with the depth 1; A MSK file created by the original Animator is exactly +8000 bytes long. There is no file header or other control information in the +file. It contains the image bit map, 1 bit per pixel, with the leftmost pixels +packed into the high order bits of each byte. The size of the image is fixed at +320x200. The image is stored left-to-right, top-to-bottom. + +EXTENSION:MSK +OCCURENCES:PC +PROGRAMS:Autodesk Animator +SEE ALSO:PIC,FLIc +--------M-MTM------------------------------- +The MTM format is generated by the Multi Track Module tracker by the demo group +Renaissance. The tracker features up to 32 channel digital music. Instead of +saving whole patterns, the tracker only saves the different tracks and the data +which tracks should be played together at which time, thus saving some pattern +space. + +OFFSET Count TYPE Description +0000h 3 char ID='MTM' +0003h 1 byte Version data + upper nibble is major version number + lower nibble is minor version number +0004h 20 char ASCIIZ song name +0018h 1 word Number of saved tracks. + ="NOT" +001Ah 1 byte Highest pattern number saved + ="NOP" +001Bh 1 byte Last order number to play(=Songlength-1) +001Ch 1 word Length of extra comment field in bytes + ="XSZ" +001Eh 1 byte Number of samples + ="NOS" +001Fh 1 byte Attribute byte (currently defined as 0) +0020h 1 byte Beats per track +0021h 1 byte Number of tracks +0022h 32 byte Pan positions of the voices + (0=left, 15=right??) +0042h "NOS" rec Instrument data + 22 char Sample name + 1 dword Sample length in bytes + 1 dword Start of sample loop in bytes + 1 dword End of sample loop in bytes + 1 byte Fine tune value for sample + 1 byte Default volume for sample + 1 byte Attribute byte, bit mapped + 0 0=8 bit sample,1=16 bit sample + 1-7 undefined (set to zero) +0042h+ 128 byte Pattern order data + "NOS"*37 +01C2h+ + "NOS"*37 "NOT" rec Track data + Each track is saved independently and has + the size of exactly 192 bytes. Each track + is arranged as 64 3-byte notes with the + following format : + 64*3 byte BYTE 0 BYTE 1 BYTE 2 + ppppppii iiiieeee aaaaaaaa + p = pitch value (0=no pitch stated) + i = instrument number (0=no instrument number) + e = effect number + a = effect argument + The effects are the standard Protracker + effects. +01C2h+ ("NOP"+1)*32 word Track sequencing data + "NOS"*37+ This is the list of which track is used + "NOT"*192 as which voice in each pattern. One track + can be part of many patterns, the drums + for example. + Track 0 is never saved but is always + considered as an empty track. That means + that counting really starts at one. + The data is organized in sets of 32 voices. + The first word contains the information which + track is used in pattern 0, voice 0. The next + word is for pattern 0, voice 1, etc., this + is repeated for each pattern, 32 words for each + saved pattern. +01C2h+ "XSZ" char Extra comment field. This contains some + "NOS"*37+ message or something. + "NOT"*192+ + ("NOP"+1)*32*2 +01C2h+ ? byte Raw sample data(unsigned). + "NOS"*37+ + "NOT"*192+ + ("NOP"+1)*32*2+ + "XSZ" +EXTENSION:MTM +SEE ALSO:MOD +OCCURENCES:PC +PROGRAMS:MMEDIT,DMP +VALIDATION: +--------M-MTS------------------------------- +The Master Tracker program by the french demo group Arkham is a tracker +for AdLib, SB and speaker - the further limits of this tracker are unknowm +to me. +OFFSET Count TYPE Description +0000h 6 char ID="MTRAC " +0006h 20 char Song name, zero padded +EXTENSION:MST +OCCURENCES:PC +PROGRAMS:Master Tracler v1.0 +SEE ALSO:MOD +--------E-MZ EXE---------------------------- +The old EXE files are the EXE files executed directly by MS-DOS. They were a +major improvement over the old 64K COM files, since EXE files can span multiple +segments. An EXE file consists of three different parts, the header, the +relocation table and the binary code. +The header is expanded by a lot of programs to store their copyright information +in the executable, some extensions are documented below. +The format of the header is as follows : +OFFSET Count TYPE Description +0000h 2 char ID='MZ' + ID='ZM' +0002h 1 word Number of bytes in last 512-byte page + of executable +0004h 1 word Total number of 512-byte pages in executable + (including the last page) +0006h 1 word Number of relocation entries +0008h 1 word Header size in paragraphs +000Ah 1 word Minimum paragraphs of memory allocated in + addition to the code size +000Ch 1 word Maximum number of paragraphs allocated in + addition to the code size +000Eh 1 word Initial SS relative to start of executable +0010h 1 word Initial SP +0012h 1 word Checksum (or 0) of executable +0014h 1 dword CS:IP relative to start of executable + (entry point) +0018h 1 word Offset of relocation table; + 40h for new-(NE,LE,LX,W3,PE etc.) executable +001Ah 1 word Overlay number (0h = main program) + +Following are the header expansions by some other prorams like TLink, LZExe and +other linkers, encryptors and compressors; all offsets are relative to the start +of the whole header : + +---new executable +OFFSET Count TYPE Description +001Ch 4 byte ???? +0020h 1 word Behaviour bits ?? +0022h 26 byte reserved (0) +003Ch 1 dword Offset of new executable header from start of + file (or 0 if plain MZ executable) + +---Borland TLINK +OFFSET Count TYPE Description +001Ch 2 byte ?? (apparently always 01h 00h) +001Eh 1 byte ID=0FBh +001Fh 1 byte TLink version, major in high nybble +0020h 2 byte ?? + +---old ARJ self-extracting archive +OFFSET Count TYPE Description +001Ch 4 char ID='RJSX' (older versions) + new signature is 'aRJsf'" in the first 1000 + bytes of the file) +---LZEXE compressed executable +OFFSET Count TYPE Description +001Ch 2 char ID='LZ' +001Eh 2 char Version number : + '09' - LZExe 0.90 + '91' - LZExe 0.91 +---PKLITE compressed executable +OFFSET Count TYPE Description +001Ch 1 byte Minor version number +001Dh 1 byte Bit mapped : + 0-3 - major version + 4 - Extra compression + 5 - Multi-segment file +001Eh 6 char ID='PKLITE' +---LHarc 1.x self-extracting archive +OFFSET Count TYPE Description +001Ch 4 byte unused??? +0020h 3 byte Jump to start of extraction code +0023h 2 byte ??? +0025h 12 char ID='LHarc's SFX ' +--LHA 2.x self-extracting archive +OFFSET Count TYPE Description +001Ch 8 byte ??? +0024h 10 char ID='LHa's SFX ' + For version 2.10 + ID='LHA's SFX ' (v2.13) + For version 2.13 +---LH self-extracting archive +OFFSET Count TYPE Description +001Ch 8 byte ??? +0024h 8 byte ID='LH's SFX ' +---TopSpeed C 3.0 CRUNCH compressed file +OFFSET Count TYPE Description +001Ch 1 dword ID=018A0001h +0020h 1 word ID=1565h +---PKARC 3.5 self-extracting archive +OFFSET Count TYPE Description +001Ch 1 dword ID=00020001h +0020h 1 word ID=0700h +---BSA (Soviet archiver) self-extracting archive +OFFSET Count TYPE Description +001Ch 1 word ID=000Fh +001Eh 1 byte ID=A7h +---LARC self-extracting archive +OFFSET Count TYPE Description +001Ch 4 byte ??? +0020h 11 byte ID='SFX by LARC ' + +After the header, there follow the relocation items, which are used to span +multpile segments. The relocation items have the following format : +OFFSET Count TYPE Description +0000h 1 word Offset within segment +0002h 1 word Segment of relocation +To get the position of the relocation within the file, you have to compute the +physical adress from the segment:offset pair, which is done by multiplying the +segment by 16 and adding the offset and then adding the offset of the binary +start. Note that the raw binary code starts on a paragraph boundary within the +executable file. All segments are relative to the start of the executable in +memory, and this value must be added to every segment if relocation is done +manually. + +EXTENSION:EXE,OVR,OVL +OCCURENCES:PC +PROGRAMS:MS-DOS +REFERENCE:Ralf Brown's Interrupt List +SEE ALSO:COM,EXE,NE EXE +--------E-NE EXE---------------------------- +The NE EXE files are the new exe files used by windows and OS/2 executables. +They contain a small MZ EXE which prints "This program requires Microsoft +Windows" or something similar but Some files contain both DOS and Windows +versions of the executable. The position of the new EXE header can be found +in the old exe header - see the MZ EXE topic for further information. All +offsets within this header are from the start of the header if not noted +otherwise. + +OFFSET Count TYPE Description +0000h 2 char ID='NE' +0002h 1 byte Linker major version +0003h 1 byte Linker minor version +0004h 1 word Offset of entry table (see below) +0006h 1 word Length of entry table in bytes +0008h 1 dword File load CRC (0 in Borland's TPW) +000Ch 1 byte Program flags, bitmapped : + 0-1 - DGroup type : + 0 - none + 1 - single shared + 2 - multiple + 3 - (null) + 2 - Global initialization + 3 - Protected mode only + 4 - 8086 instructions + 5 - 80286 instructions + 6 - 80386 instructions + 7 - 80x87 instructions +000Dh 1 byte Application flags, bitmapped + 0-2 - Application type + 1 - Full screen (not aware of + Windows/P.M. API) + 2 - Compatible with Windows/P.M. API + 3 - Uses Windows/P.M. API + 3 - OS/2 family application + 4 - reserved? + 5 - Errors in image/executable + 6 - "non-conforming program" whatever + 7 - DLL or driver (SS:SP info invalid, CS:IP + points at FAR init routine called with + AX=module handle which returns AX=0000h + on failure, AX nonzero on successful + initialization) +000Eh 1 byte Auto data segment index +0010h 1 word Initial local heap size +0012h 1 word Initial stack size +0014h 1 dword Entry point (CS:IP), + CS is index into segment table +0018h 1 dword Initial stack pointer (SS:SP) + SS is index into segment table +001Ch 1 word Segment count +001Eh 1 word Module reference count +0020h 1 word Size of nonresident names table in bytes +0022h 1 word Offset of segment table (see below) +0024h 1 word Offset of resource table +0026h 1 word Offset of resident names table +0028h 1 word Offset of module reference table +002Ah 1 word Offset of imported names table + (array of counted strings, terminated with a + string of length 00h) +002Ch 1 dword Offset from start of file to nonresident + names table +0030h 1 word Count of moveable entry point listed in + entry table +0032h 1 word File alignment size shift count + 0 is equivalent to 9 (default 512-byte pages) +0034h 1 word Number of resource table entries +0036h 1 byte Target operating system + 0 - unknown + 1 - OS/2 + 2 - Windows + 3 - European MS-DOS 4.x + 4 - Windows 386 + 5 - BOSS (Borland Operating System Services) +0037h 1 byte Other OS/2 EXE flags, bitmapped + 0 - Long filename support + 1 - 2.x protected mode + 2 - 2.x proportional fonts + 3 - Executable has gangload area +0038h 1 word Offset to return thunks or start of gangload + area - whatever that means. +003Ah 1 word offset to segment reference thunks or length + of gangload area. +003Ch 1 word Minimum code swap area size +003Eh 2 byte Expected Windows version (minor version first) + +EXTENSION:DLL,EXE,FOT +OCCURENCES:PC +PROGRAMS: +REFERENCE:Windows 3.1 SDK Programmer's Reference, Vol 4. +SEE ALSO:EXE,MZ EXE +--------H-NG-G------------------------------ +Information about this format comes only from a magic file, thus is only good +for file identification. I did not test it, since I don't have any NG files. +The Norton Guides are a popup help program for the IBM PCs which provide instant +help anywhere... + +OFFSET Count TYPE Description +0000h 2 char ID='NG' +0002h 1 dword ID=0 +EXTENSION:NG +OCCURENCES:PC +PROGRAMS:NG.EXE +SEE ALSO:TPH,HLP +--------B-OBJ------------------------------- +Most of the description was taken from the Microsoft Product Support +Services Application Note SS0288. The .OBJ files are binary files used +by compilers to link in precompiled code. They contain symbol and relocation +information necessary to link the data and code contained in the files. The +.OBJ files have no common header which makes a validation or identification +guesswork at best. The .OBJ files consist of at least one record, each of the +following type : + +OFFSET Count TYPE Description +0000h 1 byte Record type (see below) +0001h 1 word Record length + ="LEN" +0003h "LEN" byte Record data +0003h 1 byte Checksum or 0 + +"LEN" (that much for validation) + +The maximum size of the entire record (unless otherwise noted for specific +record types) is 1024 bytes. + +For LINK386, the format is determined by the least-significant bit +of the Record Type field. An odd Record Type indicates that certain +numeric fields within the record contain 32-bit values; an even +Record Type indicates that those fields contain 16-bit values. The +affected fields are described with each record. Note that this +principle does not govern the Use32/Use16 segment attribute (which +is set in the ACBP byte of SEGDEF records); it simply specifies the +size of certain numeric fields within the record. It is possible to +use 16-bit OMF records to generate 32-bit segments, or vice versa. + +LINK ignores the value of the checksum byte, but some other utilities may +not. Microsoft's Quick languages write a 0 byte instead of computing a checksum. + +The contents of each record are determined by the record type, but +certain subfields appear frequently enough to be explained separately. +The format of such fields is below. + +Names : + +A name string is encoded as an 8-bit unsigned count followed by a +string of count characters. The character set is usually some ASCII +subset. A null name is specified by a single byte of 0 (indicating a +string of length 0). + +Indexed References : + +Certain items are ordered by occurrence and are referenced by index. +The first occurrence of the item has index number 1. Index fields may +contain 0 (indicating that they are not present) or values from 1 +through 7FFF. The index number field in an object record can be either +1 or 2 bytes long. If the number is in the range 0-7FH, the high-order +bit (bit 7) is 0 and the low-order bits contain the index number, so +the field is only 1 byte long. If the index number is in the range 80- +7FFFH, the field is 2 bytes long. The + +Type Indexes : + +Type Index fields occupy 1 or 2 bytes and occur in PUBDEF, LPUBDEF, +COMDEF, LCOMDEF, EXTDEF, and LEXTDEF records. They are encoded as +described above for indexed references, but the interpretation of the +values stored is governed by whether the module has the "new" or "old" +object module format. + +"Old" versions of the OMF (indicated by lack of a COMENT record with +comment class A1), have Type Index fields that contain indexes into +previously seen TYPDEF records. This format is no longer produced by +Microsoft products and is ignored by LINK if it is present. See the +section of this document on TYPDEF records for details on how this was +used. + +"New" versions of the OMF (indicated by the presence of a COMENT +record with comment class A1), have Type Index fields that contain +proprietary CodeView information. For more information on CodeView, +see Appendix 1. + +Ordered Collections : + +Certain records and record groups are ordered so that the records may +be referred to with indexes (the format of indexes is described in the +"Indexed References" section of this document). The same format is +used whether an index refers to names, logical segments, or other +items. + +The overall ordering is obtained from the order of the records within +the file together with the ordering of repeated fields within these +records. Such ordered collections are referenced by index, counting +from 1 (index 0 indicates unknown or not specified). + +For example, there may be many LNAMES records within a module, and +each of those records may contain many names. The names are indexed +starting at 1 for the first name in the first LNAMES record +encountered while reading the file, 2 for the second name in the first +record, and so forth, with the highest index for the last name in the +last LNAMES record encountered. + +The ordered collections are: + + Names Ordered by occurrence of LNAMES records and + names within each. Referenced as a name + index. + + Logical Ordered by occurrence of SEGDEF records in + Segments file. Referenced as a segment index. + + Groups Ordered by occurrence of GRPDEF records in + file. Referenced as a group index. + + External Ordered by occurrence of EXTDEF, COMDEF, + Symbols LEXTDEF, and LCOMDEF records and symbols + within each. Referenced as an external name + index (in FIXUP subrecords). + + +Numeric 2- and 4-Byte Fields : + +Certain records, notably SEGDEF, PUBDEF, LPUBDEF, LINNUM, LEDATA, +LIDATA, FIXUPP, and MODEND, contain size, offset, and displacement +values that may be 32-bit quantities for Use32 segments. The encoding +is as follows: + + - When the least-significant bit of the record type byte is set (that + is, the record type is an odd number), the numeric fields are 4 + bytes. + + - When the least-significant bit of the record type byte is clear, + the fields occupy 2 bytes. The values are zero-extended when + applied to Use32 segments. + + NOTE: See the description of SEGDEF records in this document for an + explanation of Use16/Use32 segments. + + +The general record ordering is not mandatory, but should be (for link speed) +like this : + +THEADR or LHEADR record : + + Records Processed by LINK Pass 1 : + All records may occur in any order but must stand before the link pass + separator, if it is present. + + COMENT records identifying object format and extensions + COMENT records other than Link Pass Separator comment + LNAMES or LLNAMES records providing ordered name list + SEGDEF records providing ordered list of program segments + GRPDEF records providing ordered list of logical segments + TYPDEF records (obsolete) + ALIAS records + PUBDEF records locating and naming public symbols + LPUBDEF records locating and naming private symbols + COMDEF, LCOMDEF, EXTDEF, LEXTDEF, and CEXTDEF records + +Link Pass Separator (Optional) : + +COMENT class A2 record indicating that Pass 1 of the linker is +complete. When this record is encountered, LINK stops reading the +object file in Pass 1; no records after this comment are read in Pass +1. All the records listed above must come before this COMENT record. + +For greater linking speed, all LIDATA, LEDATA, FIXUPP, BAKPAT, INCDEF, +and LINNUM records should come after the A2 COMENT record, but this is +not required. In LINK, Pass 2 begins again at the start of the object +module, so these records are processed in Pass 2 no matter where they +are placed in the object module. + +Records Ignored by LINK Pass 1 and Processed by LINK Pass 2 : + +The following records may come before or after the Link Pass +Separator: + + LIDATA, LEDATA, or COMDAT records followed by applicable FIXUPP + records + FIXUPP records containing only THREAD subrecords + BAKPAT and NBKPAT FIXUPP records + COMENT class A0, subrecord type 03 (INCDEF) records containing + incremental compilation information for FIXUPP and LINNUM records + LINNUM and LINSYM records providing line number and program code or + data association + +Terminator : + + MODEND record indicating end of module with optional start address + +Details of each record (form and content) follow below. +Conflicts between various OMFs that overlap in their use of record +types or fields are marked. + +Below is a combined list of record types defined by the Intel 8086 OMF +specification and record types added after that specification was +finished. Titles in square brackets ([]) indicate record types that +have been implemented and that are described in this document. Titles +not in square brackets indicate record types that have not been +implemented and are followed by a paragraph of description from the +Intel specification. + +For unimplemented record types, a subtle distinction is made between +records that LINK ignores and those for which LINK generates an +"illegal object format" error condition. + +Records Currently Defined + + 6EH RHEADR R-Module Header Record + This record serves to identify a module that has + been processed (output) by LINK-86/LOCATE-86. It + also specifies the module attributes and gives + information on memory usage and need. This record + type is ignored by Microsoft LINK. + + 70H REGINT Register Initialization Record + This record provides information about the 8086 + register/register-pairs: CS and IP, SS and SP, DS + and ES. The purpose of this information is for a + loader to set the necessary registers for + initiation of execution. This record type is + ignored by Microsoft LINK. + + 72H REDATA Relocatable Enumerated Data Record + This record provides contiguous data from which a + portion of an 8086 memory image may eventually be + constructed. The data may be loaded directly by + an 8086 loader, with perhaps some base fixups. + The record may also be called a Load-Time + Locatable (LTL) Enumerated Data Record. This + record type is ignored by Microsoft LINK. + + 74H RIDATA Relocatable Iterated Data Record + This record provides contiguous data from which a + portion of an 8086 memory image may eventually be + constructed. The data may be loaded directly by + an 8086 loader, but data bytes within the record + may require expansion. The record may also be + called a Load-Time Locatable (LTL) Iterated Data + Record. This record type is ignored by Microsoft + LINK. + + 76H OVLDEF Overlay Definition Record + This record provides the overlay's name, its + location in the object file, and its attributes. + A loader may use this record to locate the data + records of the overlay in the object file. This + record type is ignored by Microsoft LINK. + + 78H ENDREC End Record + This record is used to denote the end of a set of + records, such as a block or an overlay. This + record type is ignored by Microsoft LINK. + + 7AH BLKDEF Block Definition Record + This record provides information about blocks + that were defined in the source program input to + the translator that produced the module. A BLKDEF + record will be generated for every procedure and + for every block that contains variables. This + information is used to aid debugging programs. + This record type is ignored by Microsoft LINK. + + 7CH BLKEND Block End Record + This record, together with the BLKDEF record, + provides information about the scope of variables + in the source program. Each BLKDEF record must be + followed by a BLKEND record. The order of the + BLKDEF, debug symbol records, and BLKEND records + should reflect the order of declaration in the + source module. This record type is ignored by + Microsoft LINK. + + 7EH DEBSYM Debug Symbols Record + This record provides information about all + local symbols, including stack and based symbols. + The purpose of this information is to aid debug- + ging programs. This record type is ignored by + Microsoft LINK. + + [80H] [THEADR] [Translator Header Record] + + [82H] [LHEADR] [Library Module Header Record] + + 84H PEDATA Physical Enumerated Data Record + This record provides contiguous data, + from which a portion of an 8086 memory + image may be constructed. The data + belongs to the "unnamed absolute segment" + in that it has been assigned absolute + 8086 memory addresses and has been + divorced from all logical segment + information. This record type is ignored + by Microsoft LINK. + + 86H PIDATA Physical Iterated Data Record + This record provides contiguous data, + from which a portion of an 8086 memory + image may be constructed. It allows + initialization of data segments and + provides a mechanism to reduce the size + of object modules when there is repeated + data to be used to initialize a memory + image. The data belongs to the "unnamed + absolute segment." This record type is + ignored by Microsoft LINK. + + [88H] [COMENT] [Comment Record] + + [8AH/8BH] [MODEND] [Module End Record] + + [8CH] [EXTDEF] [External Names Definition Record] + + [8EH] [TYPDEF] [Type Definition Record] + + [90H/91H] [PUBDEF] [Public Names Definition Record] + + 92H LOCSYM Local Symbols Record + This record provides information about + symbols that were used in the source + program input to the translator that + produced the module. This information is + used to aid debugging programs. This + record has a format identical to the + PUBDEF record. This record type is + ignored by Microsoft LINK. + + [94H/95H] [LINNUM] [Line Numbers Record] + + [96H] [LNAMES] [List of Names Record] + + [98H/99H] [SEGDEF] [Segment Definition Record] + + [9AH] [GRPDEF] [Group Definition Record] + + [9CH/9DH] [FIXUPP] [Fixup Record] + + 9EH (none) Unnamed record + This record number was the only even + number not defined by the original Intel + specification. Apparently it was never + used. This record type is ignored by + Microsoft LINK. + + [A0H/A1H] [LEDATA] [Logical Enumerated Data Record] + + [A2H/A3H] [LIDATA] [Logical Iterated Data Record] + + A4H LIBHED Library Header Record + This record is the first record in a library + file. It immediately precedes the modules + (if any) in the library. Following the + modules are three more records in the + following order: LIBNAM, LIBLOC, and LIBDIC. + This record type is ignored by Microsoft + LINK. + + A6H LIBNAM Library Module Names Record + This record lists the names of all the + modules in the library. The names are listed + in the same sequence as the modules appear + in the library. This record type is ignored + by Microsoft LINK. + + A8H LIBLOC Library Module Locations Record + This record provides the relative location, + within the library file, of the first byte + of the first record (either a THEADR or + LHEADR or RHEADR record) of each module in + the library. The order of the locations + corresponds to the order of the modules in + the library. This record type is ignored by + Microsoft LINK. + + AAH LIBDIC Library Dictionary Record + This record gives all the names of public + symbols within the library. The public names + are separated into groups; all names in the + nth group are defined in the nth module of + the library. This record type is ignored by + Microsoft LINK. + + [B0H] [COMDEF] [Communal Names Definition Record] + + [B2H/B3H] [BAKPAT] [Backpatch Record] + + [B4H] [LEXTDEF] [Local External Names Definition Record] + + [B6H/B7H] [LPUBDEF] [Local Public Names Definition Record] + + [B8H] [LCOMDEF] [Local Communal Names Definition Record] + + BAH/BBH COMFIX Communal Fixup Record + Microsoft doesn't support this never- + implemented IBM extension. This record type + generates an error when it is encountered by + Microsoft LINK. + + BCH CEXTDEF COMDAT External Names Definition Record + + C0H SELDEF Selector Definition Record + Microsoft doesn't support this never- + implemented IBM extension. This record type + generates an error when it is encountered by + Microsoft LINK. + + [C2H/C3] [COMDAT] [Initialized Communal Data Record] + + [C4H/C5H] [LINSYM] [Symbol Line Numbers Record] + + [C6H] [ALIAS] [Alias Definition Record] + + [C8H/C9H] [NBKPAT] [Named Backpatch Record] + + [CAH] [LLNAMES] [Local Logical Names Definition Record] + + [F0H] [Library Header Record] + Although this is not actually an OMF record + type, the presence of a record with F0H as + the first byte indicates that the module is + a Microsoft library. The format of a library + file is given in Appendix 2. + + [F1H] [Library End Record] + + +80H THEADR--TRANSLATOR HEADER RECORD + +The THEADR record contains the name of the object module. This name +identifies an object module within an object library or in messages +produced by the linker. + +OFFSET Count TYPE Description +0000h 1 byte ID=80h +0001h 1 byte Record length + ="LEN" +0002h "LEN" char Name +0002h 1 byte Checksum ++"LEN" + + +82H LHEADR--LIBRARY MODULE HEADER RECORD + +This record is very similar to the THEADR record. It is used to +indicate the name of a module within a library file (which has an +internal organization different from that of an object module). +This record type was defined in the original Intel specification with +the same format but with a different purpose, so its use for libraries +should be considered a Microsoft extension. + +OFFSET Count TYPE Description +0000h 1 byte ID=82h +0001h 1 byte Record length + ="LEN" +0002h "LEN" char Name +0002h 1 byte Checksum ++"LEN" + +EXTENSION:OBJ,OBP,OBW,LIB +OCCURENCES:PC +PROGRAMS:MS Link, TLink, OBJDUMP +REFERENCE:**** +--------H-OS/2 HELP------------------------- +The OS/2 help files are different from the WinHelp help files,since the WinHelp +format is proprietary to MicroSoft because of the patented LZ-packing they +implemented. +OFFSET Count TYPE Description +0000h 3 char ID='HSP' +0003h 1 byte Flags : + 0 - INF style file + 1-3 - unknown + 4 - HLP style file + Patching this file allows reading HLP files + using the VIEW command, while HLP files seem to + work with INF settings as well. +0005h 1 word Total size of header +0007h 1 word Unknown +????h other data +0047h ? char ASCIIZ name of the HLP/INF file +EXTENSION:HLP,INF +OCCURENCES:OS/2 +REFERENCE:INF02A.DOC +SEE ALSO:WinHelp HLP +--------X-PARADOX DATAFILES-?--------------- +The data files for the paradox database engine have the following format : + +OFFSET Count TYPE Description +0000h 1 byte Number of bytes per record +0001h 32 byte ???? +0021h 1 byte Number of fields per record +0022h 1 byte ?Password protected? / other flags ? + - if password protected, 32 more bytes seem + to be inserted. +0023h ?? byte ????? +0058h ? rec + 1 byte Field type ? + 1 - character field + 5 - currency? + 6 - integer + 1 byte Field length + +After that, my information becomes really blurry :-I There seems +to follow the name of the file, and some 0-filled areas, and after +that the "first ASCII character after 0C0h" is said to be the start +of the field names. Each field name is in ASCIZ. The actual records +start after the field names, either at the 4th byte after 00h 02h (the +sequence ending the field names section) or after 00h 02h 00h 00h 00h. + +EXTENSION:??? +OCCURENCES:PC +PROGRAMS:Paradox engine +SEE ALSO: +--------I-PBM-G----------------------------- +The PBM files are image files, which were used at least by DMGraph, an utility +to insert new graphics into a DOOM WAD file. The image dimensions seem to be +stored in ASCII format delimited with CR/LF, after that follows the raw binary +image data. +OFFSET Count TYPE Description +0000h 1 char ID='P' +0001h 1 char Bitmap type : + '1' - PBM bitmap + '2' - PGM greymap + '3' - PPM pixmap + '4' - PBM raw bitmap + '5' - PGM raw greymap + '6' - PPM raw pixmap +EXTENSION:PBM,PGM,PPM +OCCURENCES:PC +PROGRAMS:DMGraph.EXE +--------I-PCX------------------------------- +The PCX files are created by the programs of the ZSoft Paintbrush family +and the FRIEZE package by the same manufacturer. A PCX file contains only +one image, the data for this image and possibly palette information for +this image. The encoding scheme used for PCX encoding is a simple RLE +mechanism, see ALGRTHMS.txt for further information. A PCX image is stored +from the upper scan line to the lower scan line. + +The size of a decoded scan line is always an even number, thus one additional +byte should always be allocated for the decoding buffer. + +The header has a fixed size of 128 bytes and looks like this : +OFFSET Count TYPE Description +0000h 1 byte Manufacturer. + 10=ZSoft +0001h 1 byte Version information + 0=PC Paintbrush v2.5 + 2=PC Paintbrush v2.8 w palette information + 3=PC Paintbrush v2.8 w/o palette information + 4=PC Paintbrush/Windows + 5=PC Paintbrush v3.0+ +0002h 1 byte Encoding scheme, 1 = RLE, none other known +0003h 1 byte Bits per pixel +0004h 1 word left margin of image +0006h 1 word upper margin of image +0008h 1 word right margin of image +000Ah 1 word lower margin of image +000Ch 1 word Horizontal DPI resolution +000Eh 1 word Vertical DPI resolution +0010h 48 byte Color palette setting for 16-color images + 16 RGB triplets +0040h 1 byte reserved +0041h 1 byte Number of color planes + ="NCP" +0042h 1 word Number of bytes per scanline (always even, + use instead of right margin-left margin). + ="NBS" +0044h 1 word Palette information + 1=color/bw palette + 2=grayscale image +0046h 1 word Horizontal screen size +0048h 1 word Vertical screen size +004Ah 54 byte reserved, set to 0 + +The space needed to decode a single scan line is "NCP"*"NBS" bytes, the last +byte may be a junk byte which is not displayed. + +After the image data, if the version number is 5 (or greater?) there possibly +is a VGA color palette. The color ranges from 0 to 255, 0 is zero intensity, +255 is full intensity. The palette has the following format : + +OFFSET Count TYPE Description +0000h 1 byte VGA palette ID (=0Ch) +0001h 768 byte RGB triplets with palette information + +EXTENSION:PCX +OCCURENCES:PC +PROGRAMS:PC Paintbrush +SEE ALSO: +--------I-PIC------------------------------- +PIC files contain images in an uncompressed format. Both the original Animator +and Animator Pro from Autodesk produce PIC files. The file formats are +different; Animator Pro produces a hierarchial block oriented file, while the +original Animator file is a simpler fixed format. See PIC(Pro) for further +information on the Animator Pro PIC format. + +The original Animator uses this format to store a single-frame picture image. +This format description applies to both PIC and original Animator CEL files. The +file begins with a 32 byte header, as follows: + +OFFSET Count TYPE Description +0000h 1 word ID=9119h +0002h 1 word Width of image; PIC files have always a width + of 320, CEL images may have any value. +0004h 1 word Height of image, 200 for a PIC, any value for + a CEL file. +0006h 1 word X offset of image, always 0 for a PIC image, + may be nonzero in a CEL image. +0008h 1 word Y offset of image. Zero for a PIC file. +000Ah 1 byte Bits per pixel (8) +000Bh 1 byte Compresion flag, always zero +000Ch 1 dword Size of the image data in bytes +0010h 16 byte reserved(0) + +Immediately following the header is the color map. It contains all 256 palette +entries in rgb order. Each of the r, g, and b components is a single byte in the +range of 0-63. Following the color palette is the image data, one byte per +pixel, from left to right, top to bottom. +EXTENSION:PIC,CEL +OCCURENCES:PC +PROGRAMS:Autodesk Animator +SEE ALSO:CEL,FLIc,PIC(PRO) +--------I-PIC(PRO)-------------------------- +This format description applies to both PIC and MSK files created with the +Autodesk Animator Pro package. The file begins with a 64-byte header defined +as follows: + +Offset Length Name Description +0000h 1 dword The size of the whole file including the size + of this header. +0004h 1 word ID=9500h +0006h 1 word Width of the image +0008h 1 word Height of the image +000Ah 1 word X offset of image +000Ch 1 word Y offset of image +000Eh 1 dword User ID, set to zero +0012h 1 byte Bits per pixel (8 for PIC, 1 for MSK) +0013h 45 byte reserved (0) + +Following the file header are the data blocks for the image. Each data block +within a PIC or MSK file is formatted as follows: + +OFFSET Count TYPE Description +0000h 1 dword The size of the block, including this header. +0004h 1 word Data type ID : + 0 - Color palette info + 1 - Byte-per-pixel image data + 2 - Bit-per-pixel mask data +0006h ? byte Data + +The type values in the block headers indicate what type of graphics data the +block contains. + +In a PIC_CMAP block, the first 2-byte word is a version code; +currently this is set to zero. Following the version word are all 256 palette +entries in rgb order. Each of the r, g, and b components is a single byte in the +range of 0-255. This type of block appears in PIC files; there will generally be +no color map block in a MSK file. + +In a PIC_BYTEPIXELS block, the image data appears immediately following the +6-byte block header. The data is stored as one byte per pixel, in left-to-right, +topD to-bottom sequence. + +In a PIC_BITPIXELS block, the bitmap data appears immediately following the +6-byte block header. The data is stored as bits packed into bytes such that the +leftmost bits appear in the high-order positions of each byte. The bits are +stored in left-to-right, top-to bottom sequence. When the width of the bitmap is +not a multiple of 8, there will be unused bits in the low order positions of the +last byte on each line. The number of bytes per line is ((width+7)/8). This type +of block appears in MSK files. + +EXTENSION:PIC,MSK +OCCURENCES:PC +PROGRAMS:Autodesk Animator Pro +REFERENCE: +SEE ALSO:PIC,FLT +--------E-PIF------------------------------- +The Program Information Files have stayed a long time with the PC. They origi- +nated from IBMs Topview, were carried on by DoubleView and DesqView, and today +they are used by Windows and Windows NT. The PIF files store additional +information about executables that are foreign to the running multitasking +system such as ressource usage, keyboard and mouse virtualization and hotkeys. +The original (Topview) PIF had a size of 171h bytes, after that, there come the +various extensions for the different operating environments. The different +extensions are discussed in their own sections. + +OFFSET Count TYPE Description +0000h 1 byte reserved +0001h 1 byte Checksum +0002h 30 char Title for the window +0020h 1 word Maximum memory reserved for program +0022h 1 word Minimum memory reserved for program +0024h 63 char Path and filename of the program +0063h 1 byte 0 - Do not close window on exit + other - Close window on exit +0064h 1 byte Default drive (0=A: ??) +0065h 64 char Default startup directory +00A5h 64 char Parameters for program +00E5h 1 byte Initial screen mode, 0 equals mode 3 ? +00E6h 1 byte Text pages to reserve for program +00E7h 1 byte First interrupt used by program +00E8h 1 byte Last interrupt used by program +00E9h 1 byte Rows on screen +00EAh 1 byte Columns on screen +00EBh 1 byte X position of window +00ECh 1 byte Y position of window +00EDh 1 word System memory ?? whatever +00EFh 64 char ?? Shared program path +012Fh 64 char ?? Shared program data file +016Fh 1 word Program flags + +EXTENSION:PIF,DVP +OCCURENCES:PC +PROGRAMS:Topview, DesqView, Windows +REFERENCE:see DDJ #202, July 1993, QuarterDeck SDK +SEE ALSO:Windows PIF, Windows NT PIF +VALIDATION: +--------I-PLY------------------------------- +The PoLYgon files created by the Autodesk Animator packages contain a set of +points that describe a polygon. +OFFSET Count TYPE Description +0000h 1 word Number of points in the file +0002h 1 dword reserved (0) +0006h 1 byte Closed shape flag. If nonzero there is an + implied connection between the last and the + first point. If it is zero, the shape is open. +0007h 1 byte ID=99h + +After the header, there follows the point data, organized in records like this : +OFFSET Count TYPE Description +0000h 1 word X coordinate +0002h 1 word Y coordinate +0006h 1 word Z coordinate, always zero + +EXTENSION:PLY +OCCURENCES:PC +PROGRAMS:Autodesk Animator +--------I-PNG-M----------------------------- +"excerpted from the PNG (Portable Network Graphics) specification, tenth draft." + +The PNG format (pronounced PiNG) was the replacement the Internet found, after +the GIF format/CompuServe/LZW compression-patent stuff. PNG is a lossless image- +compression format, which allows a large range of applications. The PNG format +is in the public domain, the latest versions of the standard and related +information can always be found at the PNG FTP archive site, +ftp.uu.net:/graphics/png/. The maintainers of the PNG specification can be +contacted by e-mail at png-info@uunet.uu.net. + +The PNG format uses Motorola byte order, scanlines always begin on byte +boundaries. When pixels are less than 8 bits deep, if the scanline width is not +evenly divisible by the number of pixels per byte then the low-order bits in the +last byte of each scanline are wasted. The contents of the padding bits added to +fill out the last byte of a scanline are unspecified. + +An additional "filter" byte is added to the beginning of every scanline, +as described in detail below. The filter byte is not considered part of the +image data, but it is included in the data stream sent to the compression +step. + +PNG allows the image data to be filtered before it is compressed. The +purpose of filtering is to improve the compressibility of the data. The +filter step itself does not reduce the size of the data. All PNG filters are +strictly lossless. + +PNG defines several different filter algorithms, including "none" which +indicates no filtering. The filter algorithm is specified for each scanline +by a filter type byte which precedes the filtered scanline in the +precompression data stream. An intelligent encoder may switch filters +from one scanline to the next. The method for choosing which filter to +employ is up to the encoder. + +A PNG image can be stored in interlaced order to allow progressive +display. The purpose of this feature is to allow images to "fade in" when +they are being displayed on-the-fly. Interlacing slightly expands the file +size on average, but it gives the user a meaningful display much more +rapidly. Note that decoders are required to be able to read interlaced +images, whether or not they actually perform progressive display. + +With interlace type 0, pixels are stored sequentially from left to right, +and scanlines sequentially from top to bottom (no interlacing). + +Interlace type 1, known as Adam7 after its author, Adam M. Costello, +consists of seven distinct passes over the image. Each pass transmits a +subset of the pixels in the image. The pass in which each pixel is +transmitted is defined by replicating the following 8-by-8 pattern over +the entire image, starting at the upper left corner: + +1 6 4 6 2 6 4 6 +7 7 7 7 7 7 7 7 +5 6 5 6 5 6 5 6 +7 7 7 7 7 7 7 7 +3 6 4 6 3 6 4 6 +7 7 7 7 7 7 7 7 +5 6 5 6 5 6 5 6 +7 7 7 7 7 7 7 7 + +Within each pass, the selected pixels are transmitted left to right within +a scanline, and selected scanlines sequentially from top to bottom. For +example, pass 2 contains pixels 4, 12, 20, etc. of scanlines 0, 8, 16, etc. +(numbering from 0,0 at the upper left corner). The last pass contains the +entirety of scanlines 1, 3, 5, etc. + +The data within each pass is laid out as though it were a complete +image of the appropriate dimensions. For example, if the complete +image is 8x8 pixels, then pass 3 will contain a single scanline containing +two pixels. When pixels are less than 8 bits deep, each such scanline is +padded to fill an integral number of bytes (see Image layout). Filtering is +done on this reduced image in the usual way, and a filter type byte is +transmitted before each of its scanlines (see Filter Algorithms). Notice +that the transmission order is defined so that all the scanlines +transmitted in a pass will have the same number of pixels; this is +necessary for proper application of some of the filters. + +Caution: If the image contains fewer than five columns or fewer than +five rows, some passes will be entirely empty. Encoder and decoder +authors must be careful to handle this case correctly. In particular, filter +bytes are only associated with nonempty scanlines; no filter bytes are +present in an empty pass. + +A PNG file consists of a PNG signature followed by a series of chunks. +This chapter defines the signature and the basic properties of chunks. +Individual chunk types are discussed in the next chapter. + + +PNG Header +OFFSET Count TYPE Description +0000h 8 char ID=89h,'PNG',13,10,26,10 + +Chunk layout +OFFSET Count TYPE Description +0000h 1 dword Number of data bytes after this header. +0004h 4 char Chunk type. + A 4-byte chunk type code. For convenience in + description and in examining PNG files, type + codes are restricted to consist of uppercase + and lowercase ASCII letters (A-Z, a-z). + However, encoders and decoders should treat the + codes as fixed binary values, not character + strings. For example, it would not be correct + to represent the type code IDAT by the EBCDIC + equivalents of those letters. +????h ? byte Data +????h 1 dword CRC calculated on the preceding bytes in that + chunk, including the chunk type code and chunk + data fields, but not including the length + field. The CRC is always present, even for + empty chunks such as IEND. The CRC algorithm + is specified below. + +Chunk naming conventions +======================== + +Chunk type codes are assigned in such a way that a decoder can +determine some properties of a chunk even if it does not recognize the +type code. These rules are intended to allow safe, flexible extension of +the PNG format, by allowing a decoder to decide what to do when it +encounters an unknown chunk. The naming rules are not normally of +interest when a decoder does recognize the chunk's type. + +Four bits of the type code, namely bit 5 (value 32) of each byte, are used +to convey chunk properties. This choice means that a human can read +off the assigned properties according to whether each letter of the type +code is uppercase (bit 5 is 0) or lowercase (bit 5 is 1). However, decoders +should test the properties of an unknown chunk by numerically testing +the specified bits; testing whether a character is uppercase or lowercase +is inefficient, and even incorrect if a locale-specific case definition is +used. + +It is also worth noting that the property bits are an inherent part of the +chunk name, and hence are fixed for any chunk type. Thus, TEXT and +Text are completely unrelated chunk type codes. Decoders should +recognize codes by simple four-byte literal comparison; it is incorrect to +perform case conversion on type codes. + +The semantics of the property bits are: + +First Byte: 0 (uppercase) = critical, 1 (lowercase) = ancillary + Chunks which are not strictly necessary in order to meaningfully + display the contents of the file are known as "ancillary" chunks. + Decoders encountering an unknown chunk in which the + ancillary bit is 1 may safely ignore the chunk and proceed to + display the image. The time chunk (tIME) is an example of an + ancillary chunk. + + Chunks which are critical to the successful display of the file's + contents are called "critical" chunks. Decoders encountering an + unknown chunk in which the ancillary bit is 0 must indicate to + the user that the image contains information they cannot safely + interpret. The image header chunk (IHDR) is an example of a + critical chunk. + +Second Byte: 0 (uppercase) = public, 1 (lowercase) = private + If the chunk is public (part of this specification or a later edition + of this specification), its second letter is uppercase. If your + application requires proprietary chunks, and you have no interest + in seeing the software of other vendors recognize them, use a + lowercase second letter in the chunk name. Such names will + never be assigned in the official specification. Note that there is + no need for software to test this property bit; it simply ensures + that private and public chunk names will not conflict. + +Third Byte: reserved, must be 0 (uppercase) always + The significance of the case of the third letter of the chunk name + is reserved for possible future expansion. At the present time all + chunk names must have uppercase third letters. + +Fourth Byte: 0 (uppercase) = unsafe to copy, 1 (lowercase) = safe to copy + This property bit is not of interest to pure decoders, but it is + needed by PNG editors (programs that modify a PNG file). + + If a chunk's safe-to-copy bit is 1, the chunk may be copied to a + modified PNG file whether or not the software recognizes the + chunk type, and regardless of the extent of the file modifications. + + If a chunk's safe-to-copy bit is 0, it indicates that the chunk + depends on the image data. If the program has made any + changes to critical chunks, including addition, modification, + deletion, or reordering of critical chunks, then unrecognized + unsafe chunks must not be copied to the output PNG file. (Of + course, if the program does recognize the chunk, it may choose + to output an appropriately modified version.) + + A PNG editor is always allowed to copy all unrecognized chunks + if it has only added, deleted, or modified ancillary chunks. This + implies that it is not permissible to make ancillary chunks that + depend on other ancillary chunks. + + PNG editors that do not recognize a critical chunk must report + an error and refuse to process that PNG file at all. The + safe/unsafe mechanism is intended for use with ancillary chunks. + The safe-to-copy bit will always be 0 for critical chunks. + +For example, the hypothetical chunk type name "bLOb" has the +property bits: + + bLOb <-- 32 bit Chunk Name represented in ASCII form + |||| + |||'- Safe to copy bit is 1 (lower case letter; bit 5 of byte is 1) + ||'-- Reserved bit is 0 (upper case letter; bit 5 of byte is 0) + |'--- Private bit is 0 (upper case letter; bit 5 of byte is 0) + '---- Ancillary bit is 1 (lower case letter; bit 5 of byte is 1) + +Therefore, this name represents an ancillary, public, safe-to-copy +chunk. + +See Rationale: Chunk naming conventions. + +CRC algorithm +============= + +Chunk CRCs are calculated using standard CRC methods with pre and +post conditioning. The CRC polynomial employed is as follows: + +x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 + +The 32-bit CRC register is initialized to all 1's, and then the data from +each byte is processed from the least significant bit (1) to the most +significant bit (128). After all the data bytes are processed, the CRC +register is inverted (its ones complement is taken). This value is +transmitted (stored in the file) MSB first. For the purpose of separating +into bytes and ordering, the least significant bit of the 32-bit CRC is +defined to be the coefficient of the x^31 term. + +Practical calculation of the CRC always employs a precalculated table +to greatly accelerate the computation. See Appendix: Sample CRC +Code. + +4. Chunk Specifications +======================= + +This chapter defines the standard types of PNG chunks. + +Critical Chunks +=============== + +All implementations must understand and successfully render the +standard critical chunks. A valid PNG image must contain an IHDR +chunk, one or more IDAT chunks, and an IEND chunk. + +IHDR Image Header + This chunk must appear FIRST. Its contents are: + + Width: 4 bytes + Height: 4 bytes + Bit depth: 1 byte + Color type: 1 byte + Compression type: 1 byte + Filter type: 1 byte + Interlace type: 1 byte + + Width and height give the image dimensions in pixels. They are + 4-byte integers. Zero is an invalid value. The maximum for each + is (2^31)-1 in order to accommodate languages which have + difficulty with unsigned 4-byte values. + + Bit depth is a single-byte integer giving the number of bits per + pixel (for palette images) or per sample (for grayscale and + truecolor images). Valid values are 1, 2, 4, 8, and 16, although + not all values are allowed for all color types. + + Color type is a single-byte integer that describes the + interpretation of the image data. Color type values represent + sums of the following values: 1 (palette used), 2 (color used), and + 4 (full alpha used). Valid values are 0, 2, 3, 4, and 6. + + Bit depth restrictions for each color type are imposed both to + simplify implementations and to prohibit certain combinations + that do not compress well in practice. Decoders must support all + legal combinations of bit depth and color type. (Note that bit + depths of 16 are easily supported on 8-bit display hardware by + dropping the least significant byte.) The allowed combinations + are: + + Color Allowed Interpretation + Type Bit Depths + + 0 1,2,4,8,16 Each pixel value is a grayscale level. + + 2 8,16 Each pixel value is an R,G,B series. + + 3 1,2,4,8 Each pixel value is a palette index; + a PLTE chunk must appear. + + 4 8,16 Each pixel value is a grayscale level, + followed by an alpha channel level. + + 6 8,16 Each pixel value is an R,G,B series, + followed by an alpha channel level. + + Compression type is a single-byte integer that indicates the + method used to compress the image data. At present, only + compression type 0 (deflate/inflate compression with a 32K + sliding window) is defined. All standard PNG images must be + compressed with this scheme. The compression type code is + provided for possible future expansion or proprietary variants. + Decoders must check this byte and report an error if it holds an + unrecognized code. See Deflate/Inflate Compression for details. + + Filter type is a single-byte integer that indicates the + preprocessing method applied to the image data before + compression. At present, only filter type 0 (adaptive filtering + with five basic filter types) is defined. As with the compression + type code, decoders must check this byte and report an error if it + holds an unrecognized code. See Filter Algorithms for details. + + Interlace type is a single-byte integer that indicates the + transmission order of the pixel data. Two values are currently + defined: 0 (no interlace) or 1 (Adam7 interlace). See Interlaced + data order for details. + +PLTE Palette + This chunk's contents are from 1 to 256 palette entries, each a + three-byte series of the form: + + red: 1 byte (0 = black, 255 = red) + green: 1 byte (0 = black, 255 = green) + blue: 1 byte (0 = black, 255 = blue) + + The number of entries is determined from the chunk length. A + chunk length not divisible by 3 is an error. + + This chunk must appear for color type 3, and may appear for + color types 2 and 6. If this chunk does appear, it must precede the + first IDAT chunk. There cannot be more than one PLTE chunk. + + For color type 3 (palette data), the PLTE chunk is required. The + first entry in PLTE is referenced by pixel value 0, the second by + pixel value 1, etc. The number of palette entries must not exceed + the range that can be represented by the bit depth (for example, + 2^4 = 16 for a bit depth of 4). It is permissible to have fewer + entries than the bit depth would allow. In that case, any + out-of-range pixel value found in the image data is an error. + + For color types 2 and 6 (truecolor), the PLTE chunk is optional. + If present, it provides a recommended set of from 1 to 256 colors + to which the truecolor image may be quantized if the viewer + cannot display truecolor directly. If PLTE is not present, such a + viewer must select colors on its own, but it is often preferable for + this to be done once by the encoder. + + Note that the palette uses 8 bits (1 byte) per value regardless of + the image bit depth specification. In particular, the palette is 8 + bits deep even when it is a suggested quantization of a 16-bit + truecolor image. + +IDAT Image Data + This chunk contains the actual image data. To create this data, + begin with image scanlines represented as described under Image + layout; the layout and total size of this raw data are determinable + from the IHDR fields. Then filter the image data according to + the filtering method specified by the IHDR chunk. (Note that + with filter method 0, the only one currently defined, this implies + prepending a filter type byte to each scanline.) Finally, compress + the filtered data using the compression method specified by the + IHDR chunk. The IDAT chunk contains the output datastream + of the compression algorithm. To read the image data, reverse + this process. + + There may be multiple IDAT chunks; if so, they must appear + consecutively with no other intervening chunks. The compressed + datastream is then the concatenation of the contents of all the + IDAT chunks. The encoder may divide the compressed data + stream into IDAT chunks as it wishes. (Multiple IDAT chunks + are allowed so that encoders can work in a fixed amount of + memory; typically the chunk size will correspond to the encoder's + buffer size.) It is important to emphasize that IDAT chunk + boundaries have no semantic significance and can appear at any + point in the compressed datastream. A PNG file in which each + IDAT chunk contains only one data byte is legal, though + remarkably wasteful of space. (For that matter, zero-length + IDAT chunks are legal, though even more wasteful.) + + See Filter Algorithms and Deflate/Inflate Compression for + details. + +IEND Image Trailer + This chunk must appear LAST. It marks the end of the PNG + data stream. The chunk's data field is empty. + +Ancillary Chunks +================ + +All ancillary chunks are optional, in the sense that encoders need not +write them and decoders may ignore them. However, encoders are +encouraged to write the standard ancillary chunks when the +information is available, and decoders are encouraged to interpret these +chunks when appropriate and feasible. + +The standard ancillary chunks are listed in alphabetical order. This is +not necessarily the order in which they would appear in a file. + +bKGD Background Color + This chunk specifies a default background color against which + the image may be presented. Note that viewers are not bound to + honor this chunk; a viewer may choose to use a different + background color. + + For color type 3 (palette), the bKGD chunk contains: + + palette index: 1 byte + + The value is the palette index of the color to be used as + background. + + For color types 0 and 4 (grayscale, with or without alpha), bKGD + contains: + + gray: 2 bytes, range 0 .. (2^bitdepth) - 1 + + (For consistency, 2 bytes are used regardless of the image bit + depth.) The value is the gray level to be used as background. + + For color types 2 and 6 (RGB, with or without alpha), bKGD + contains: + + red: 2 bytes, range 0 .. (2^bitdepth) - 1 + green: 2 bytes, range 0 .. (2^bitdepth) - 1 + blue: 2 bytes, range 0 .. (2^bitdepth) - 1 + + (For consistency, 2 bytes per sample are used regardless of the + image bit depth.) This is the RGB color to be used as background. + + When present, the bKGD chunk must precede the first IDAT + chunk, and must follow the PLTE chunk, if any. + + See Recommendations for Decoders: Background color. + +cHRM Primary Chromaticities and White Point + Applications that need precise specification of colors in a PNG + file may use this chunk to specify the chromaticities of the red, + green, and blue primaries used in the image, and the referenced + white point. These values are based on the 1931 CIE + (International Color Committee) XYZ color space. Only the + chromaticities (x and y) are specified. The chunk layout is: + + White Point x: 4 bytes + White Point y: 4 bytes + Red x: 4 bytes + Red y: 4 bytes + Green x: 4 bytes + Green y: 4 bytes + Blue x: 4 bytes + Blue y: 4 bytes + + Each value is encoded as a 4-byte unsigned integer, representing + the x or y value times 100000. + + If the cHRM chunk appears, it must precede the first IDAT + chunk, and it must also precede the PLTE chunk if present. + +gAMA Gamma Correction + The gamma correction chunk specifies the gamma of the + camera (or simulated camera) that produced the image, and + thus the gamma of the image with respect to the original scene. + Note that this is not the same as the gamma of the display device + that will reproduce the image correctly. + + The chunk's contents are: + + Image gamma value: 4 bytes + + A value of 100000 represents a gamma of 1.0, a value of 45000 a + gamma of 0.45, and so on (divide by 100000.0). Values around + 1.0 and around 0.45 are common in practice. + + If the encoder does not know the gamma value, it should not + write a gamma chunk; the absence of a gamma chunk indicates + the gamma is unknown. + + If the gAMA chunk appears, it must precede the first IDAT + chunk, and it must also precede the PLTE chunk if present. + + See Gamma correction, Recommendations for Encoders: + Encoder gamma handling, and Recommendations for Decoders: + Decoder gamma handling. + +hIST Image Histogram + The histogram chunk gives the approximate usage frequency of + each color in the color palette. A histogram chunk may appear + only when a palette chunk appears. If a viewer is unable to + provide all the colors listed in the palette, the histogram may + help it decide how to choose a subset of the colors for display. + + This chunk's contents are a series of 2-byte (16 bit) unsigned + integers. There must be exactly one entry for each entry in the + PLTE chunk. Each entry is proportional to the fraction of pixels + in the image that have that palette index; the exact scale factor + is chosen by the encoder. + + Histogram entries are approximate, with the exception that a + zero entry specifies that the corresponding palette entry is not + used at all in the image. It is required that a histogram entry be + nonzero if there are any pixels of that color. + + When the palette is a suggested quantization of a truecolor + image, the histogram is necessarily approximate, since a decoder + may map pixels to palette entries differently than the encoder + did. In this situation, zero entries should not appear. + + The hIST chunk, if it appears, must follow the PLTE chunk, and + must precede the first IDAT chunk. + + See Rationale: Palette histograms, and Recommendations for + Decoders: Palette histogram usage. + +pHYs Physical Pixel Dimensions + This chunk specifies the intended resolution for display of the + image. The chunk's contents are: + + 4 bytes: pixels per unit, X axis (unsigned integer) + 4 bytes: pixels per unit, Y axis (unsigned integer) + 1 byte: unit specifier + + The following values are legal for the unit specifier: + + 0: unit is unknown (pHYs defines pixel aspect ratio only) + 1: unit is the meter + + Conversion note: one inch is equal to exactly 0.0254 meters. + + If this ancillary chunk is not present, pixels are assumed to be + square, and the physical size of each pixel is unknown. + + If present, this chunk must precede the first IDAT chunk. + + See Recommendations for Decoders: Pixel dimensions. + +sBIT Significant Bits + To simplify decoders, PNG specifies that only certain bit depth + values be used, and further specifies that pixel values must be + scaled to the full range of possible values at that bit depth. + However, the sBIT chunk is provided in order to store the + original number of significant bits, since this information may be + of use to some decoders. We recommend that an encoder emit an + sBIT chunk if it has converted the data from a different bit + depth. + + For color type 0 (grayscale), the sBIT chunk contains a single + byte, indicating the number of bits which were significant in the + source data. + + For color type 2 (RGB truecolor), the sBIT chunk contains + three bytes, indicating the number of bits which were significant + in the source data for the red, green, and blue channels, + respectively. + + For color type 3 (palette color), the sBIT chunk contains three + bytes, indicating the number of bits which were significant in the + source data for the red, green, and blue components of the + palette entries, respectively. + + For color type 4 (grayscale with alpha channel), the sBIT chunk + contains two bytes, indicating the number of bits which were + significant in the source grayscale data and the source alpha + channel data, respectively. + + For color type 6 (RGB truecolor with alpha channel), the sBIT + chunk contains four bytes, indicating the number of bits which + were significant in the source data for the red, green, blue and + alpha channels, respectively. + + Note that sBIT does not have any implications for the + interpretation of the stored image: the bit depth indicated by + IHDR is the correct depth. sBIT is only an indication of the + history of the image. However, an sBIT chunk showing a bit + depth less than the IHDR bit depth does mean that not all + possible color values occur in the image; this fact may be of use to + some decoders. + + If the sBIT chunk appears, it must precede the first IDAT + chunk, and it must also precede the PLTE chunk if present. + +tEXt Textual Data + Any textual information that the encoder wishes to record with + the image is stored in tEXt chunks. Each tEXt chunk contains + a keyword and a text string, in the format: + + Keyword: n bytes (character string) + Null separator: 1 byte + Text: n bytes (character string) + + The keyword and text string are separated by a zero byte (null + character). Neither the keyword nor the text string may contain + a null character. Note that the text string is not null-terminated + (the length of the chunk is sufficient information to locate the + ending). The keyword must be at least one character and less + than 80 characters long. The text string may be of any length + from zero bytes up to the maximum permissible chunk size. + + Any number of tEXt chunks may appear, and more than one + with the same keyword is permissible. + + The keyword indicates the type of information represented by + the text string. The following keywords are predefined and + should be used where appropriate: + + Title Short (one line) title or caption for image + Author Name of image's creator + Copyright Copyright notice + Description Description of image (possibly long) + Software Software used to create the image + Disclaimer Legal disclaimer + Warning Warning of nature of content + Source Device used to create the image + Comment Miscellaneous comment; conversion from GIF comment + + Other keywords, containing any sequence of printable characters + in the character set, may be invented for other purposes. + Keywords of general interest may be registered with the + maintainers of the PNG specification. + + Keywords must be spelled exactly as registered, so that decoders + may use simple literal comparisons when looking for particular + keywords. In particular, keywords are considered case-sensitive. + + Both keyword and text are interpreted according to the ISO + 8859-1 (Latin-1) character set. Newlines in the text string + should be represented by a single linefeed character (decimal + 10); use of other ASCII control characters is discouraged. + + See Recommendations for Encoders: Text chunk processing and + Recommendations for Decoders: Text chunk processing. + +tIME Image Last-Modification Time + This chunk gives the time of the last image modification (not the + time of initial image creation). The chunk contents are: + + 2 bytes: Year (complete; for example, 1995, not 95) + 1 byte: Month (1-12) + 1 byte: Day (1-31) + 1 byte: Hour (0-23) + 1 byte: Minute (0-59) + 1 byte: Second (0-60) (yes, 60, for leap seconds; not 61, a common error) + + Universal Time (UTC, also called GMT) should be specified + rather than local time. + +tRNS Transparency + Transparency is an alternative to the full alpha channel. + Although transparency is not as elegant as the full alpha + channel, it requires less storage space and is sufficient for many + common cases. + + For color type 3 (palette), this chunk's contents are a series of + alpha channel bytes, corresponding to entries in the PLTE + chunk: + + Alpha for palette index 0: 1 byte + Alpha for palette index 1: 1 byte + etc. + + Each entry indicates that pixels of that palette index should be + treated as having the specified alpha value. Alpha values have + the same interpretation as in an 8-bit full alpha channel: 0 is + fully transparent, 255 is fully opaque, regardless of image bit + depth. The tRNS chunk may contain fewer alpha channel bytes + than there are palette entries. In this case, the alpha channel + value for all remaining palette entries is assumed to be 255. In + the common case where only palette index 0 need be made + transparent, only a one-byte tRNS chunk is needed. The tRNS + chunk may not contain more bytes than there are palette entries. + + For color type 0 (grayscale), the tRNS chunk contains a single + gray level value, stored in the format + + gray: 2 bytes, range 0 .. (2^bitdepth) - 1 + + (For consistency, 2 bytes are used regardless of the image bit + depth.) Pixels of the specified gray level are to be treated as + transparent (equivalent to alpha value 0); all other pixels are to + be treated as fully opaque (alpha value (2^bitdepth)-1). + + For color type 2 (RGB), the tRNS chunk contains a single RGB + color value, stored in the format + + red: 2 bytes, range 0 .. (2^bitdepth) - 1 + green: 2 bytes, range 0 .. (2^bitdepth) - 1 + blue: 2 bytes, range 0 .. (2^bitdepth) - 1 + + (For consistency, 2 bytes per sample are used regardless of the + image bit depth.) Pixels of the specified color value are to be + treated as transparent (equivalent to alpha value 0); all other + pixels are to be treated as fully opaque (alpha value + (2^bitdepth)-1). + + tRNS is prohibited for color types 4 and 6, since a full alpha + channel is already present in those cases. + + Note: when dealing with 16-bit grayscale or RGB data, it is + important to compare both bytes of the sample values to + determine whether a pixel is transparent. Although decoders + may drop the low-order byte of the samples for display, this must + not occur until after the data has been tested for transparency. + For example, if the grayscale level 0x0001 is specified to be + transparent, it would be incorrect to compare only the + high-order byte and decide that 0x0002 is also transparent. + + When present, the tRNS chunk must precede the first IDAT + chunk, and must follow the PLTE chunk, if any. + +zTXt Compressed Textual Data + A zTXt chunk contains textual data, just as tEXt does; + however, zTXt takes advantage of compression. + + A zTXt chunk begins with an uncompressed Latin-1 keyword + followed by a null (0) character, just as in the tEXt chunk. The + next byte after the null contains a compression type byte, for + which the only presently legitimate value is zero (deflate/inflate + compression). The compression-type byte is followed by a + compressed data stream which makes up the remainder of the + chunk. Decompression of this data stream yields Latin-1 text + which is equivalent to the text stored in a tEXt chunk. + + Any number of zTXt and tEXt chunks may appear in the same + file. See the preceding definition of the tEXt chunk for the + predefined keywords and the exact format of the text. + + See Deflate/Inflate Compression, Recommendations for + Encoders: Text chunk processing, and Recommendations for + Decoders: Text chunk processing. + +Summary of Standard Chunks +========================== + +This table summarizes some properties of the standard chunk types. + +Critical chunks (must appear in this order, except PLTE is optional): + + Name Multiple Ordering constraints + OK? + + IHDR No Must be first + PLTE No Before IDAT + IDAT Yes Multiple IDATs must be consecutive + IEND No Must be last + +Ancillary chunks (need not appear in this order): + + Name Multiple Ordering constraints + OK? + + cHRM No Before PLTE and IDAT + gAMA No Before PLTE and IDAT + sBIT No Before PLTE and IDAT + bKGD No After PLTE; before IDAT + hIST No After PLTE; before IDAT + tRNS No After PLTE; before IDAT + pHYs No Before IDAT + tIME No None + tEXt Yes None + zTXt Yes None + +Standard keywords for tEXt and zTXt chunks: + +Title Short (one line) title or caption for image +Author Name of image's creator +Copyright Copyright notice +Description Description of image (possibly long) +Software Software used to create the image +Disclaimer Legal disclaimer +Warning Warning of nature of content +Source Device used to create the image +Comment Miscellaneous comment; conversion from GIF comment + +Additional Chunk Types +====================== + +Additional public PNG chunk types are defined in the document "PNG +Special-Purpose Public Chunks", available by FTP from +ftp.uu.net:/graphics/png/ or via WWW from +http://sunsite.unc.edu/boutell/pngextensions.html. + +5. Deflate/Inflate Compression +============================== + +PNG compression type 0 (the only compression method presently +defined for PNG) specifies deflate/inflate compression with a 32K +window. Deflate compression is an LZ77 derivative used in zip, gzip, +pkzip and related programs. Extensive research has been done +supporting its patent-free status. Portable C implementations are freely +available. + +Documentation and C code for deflate are available from the Info-Zip +archives at ftp.uu.net:/pub/archiving/zip/. + +Deflate-compressed datastreams within PNG are stored in the "zlib" +format, which has the structure: + +Compression method/flags code: 1 byte +Additional flags/check bits: 1 byte +Compressed data blocks: n bytes +Checksum: 4 bytes + +Further details on this format may be found in the zlib specification. At +this writing, the zlib specification is at draft 3.1, and is available from +ftp.uu.net:/pub/archiving/zip/doc/zlib-3.1.doc. + +For PNG compression type 0, the zlib compression method/flags code +must specify method code 8 ("deflate" compression) and an LZ77 +window size of not more than 32K. + +The checksum stored at the end of the zlib datastream is calculated on +the uncompressed data represented by the datastream. Note that the +algorithm used is not the same as the CRC calculation used for PNG +chunk checksums. Verifying the chunk CRCs provides adequate +confidence that the PNG file has been transmitted undamaged. The zlib +checksum is useful mainly as a crosscheck that the deflate and inflate +algorithms are implemented correctly. + +In a PNG file, the concatenation of the contents of all the IDAT chunks +makes up a zlib datastream as specified above. This datastream +decompresses to filtered image data as described elsewhere in this +document. + +It is important to emphasize that the boundaries between IDAT chunks +are arbitrary and may fall anywhere in the zlib datastream. There is not +necessarily any correlation between IDAT chunk boundaries and deflate +block boundaries or any other feature of the zlib data. For example, it is +entirely possible for the terminating zlib checksum to be split across +IDAT chunks. + +PNG also uses zlib datastreams in zTXt chunks. In a zTXt chunk, the +remainder of the chunk following the compression type code byte is a +zlib datastream as specified above. This datastream decompresses to the +user-readable text described by the chunk's keyword. Unlike the image +data, such datastreams are not split across chunks; each zTXt chunk +contains an independent zlib datastream. + +6. Filter Algorithms +==================== + +This chapter describes the pixel filtering algorithms which may be +applied in advance of compression. The purpose of these filters is to +prepare the image data for optimum compression. + +PNG defines five basic filtering algorithms, which are given numeric +codes as follows: + +Code Name +0 None +1 Sub +2 Up +3 Average +4 Paeth + +The encoder may choose which algorithm to apply on a +scanline-by-scanline basis. In the image data sent to the compression +step, each scanline is preceded by a filter type byte containing the +numeric code of the filter algorithm used for that scanline. + +Filtering algorithms are applied to bytes, not to pixels, regardless of the +bit depth or color type of the image. The filtering algorithms work on +the byte sequence formed by a scanline that has been represented as +described under Image layout. + +When the image is interlaced, each pass of the interlace pattern is +treated as an independent image for filtering purposes. The filters work +on the byte sequences formed by the pixels actually transmitted during a +pass, and the "previous scanline" is the one previously transmitted in the +same pass, not the one adjacent in the complete image. Note that the +subimage transmitted in any one pass is always rectangular, but is of +smaller width and/or height than the complete image. Filtering is not +applied when this subimage is empty. + +For all filters, the bytes "to the left of" the first pixel in a scanline must +be treated as being zero. For filters that refer to the prior scanline, the +entire prior scanline must be treated as being zeroes for the first scanline +of an image (or of a pass of an interlaced image). + +To reverse the effect of a filter, the decoder must use the decoded values +of the prior pixel on the same line, the pixel immediately above the +current pixel on the prior line, and the pixel just to the left of the pixel +above. This implies that at least one scanline's worth of image data must +be stored by the decoder at all times. Even though some filter types do +not refer to the prior scanline, the decoder must always store each +scanline as it is decoded, since the next scanline might use a filter that +refers to it. + +PNG imposes no restriction on which filter types may be applied to an +image. However, the filters are not equally effective on all types of data. +See Recommendations for Encoders: Filter selection. + +Filter type 0: None +=================== + +With the None filter, the scanline is transmitted unmodified; it is only +necessary to insert a filter type byte before the data. + +Filter type 1: Sub +================== + +The Sub filter transmits the difference between each byte and the value +of the corresponding byte of the prior pixel. + +To compute the Sub filter, apply the following formula to each byte of +each scanline: + + Sub(x) = Raw(x) - Raw(x-bpp) + +where x ranges from zero to the number of bytes representing that +scanline minus one, Raw(x) refers to the raw data byte at that byte +position in the scanline, and bpp is defined as the number of bytes per +complete pixel, rounding up to one. For example, for color type 2 with a +bit depth of 16, bpp is equal to 6 (three channels, two bytes per channel); +for color type 0 with a bit depth of 2, bpp is equal to 1 (rounding up); for +color type 4 with a bit depth of 16, bpp is equal to 4 (two-byte grayscale +value, plus two-byte alpha channel). + +Note this computation is done for each byte, regardless of bit depth. In a +16-bit image, MSBs are differenced from the preceding MSB and LSBs +are differenced from the preceding LSB, because of the way that bpp is +defined. + +Unsigned arithmetic modulo 256 is used, so that both the inputs and +outputs fit into bytes. The sequence of Sub values is transmitted as the +filtered scanline. + +For all x < 0, assume Raw(x) = 0. + +To reverse the effect of the Sub filter after decompression, output the +following value: + + Sub(x) + Raw(x-bpp) + +(computed mod 256), where Raw refers to the bytes already decoded. + +Filter type 2: Up +================= + +The Up filter is just like the Sub filter except that the pixel immediately +above the current pixel, rather than just to its left, is used as the +predictor. + +To compute the Up filter, apply the following formula to each byte of +each scanline: + + Up(x) = Raw(x) - Prior(x) + +where x ranges from zero to the number of bytes representing that +scanline minus one, Raw(x) refers to the raw data byte at that byte +position in the scanline, and Prior(x) refers to the unfiltered bytes of +the prior scanline. + +Note this is done for each byte, regardless of bit depth. Unsigned +arithmetic modulo 256 is used, so that both the inputs and outputs fit +into bytes. The sequence of Up values is transmitted as the filtered +scanline. + +On the first scanline of an image (or of a pass of an interlaced image), +assume Prior(x) = 0 for all x. + +To reverse the effect of the Up filter after decompression, output the +following value: + + Up(x) + Prior(x) + +(computed mod 256), where Prior refers to the decoded bytes of the +prior scanline. + +Filter type 3: Average +====================== + +The Average filter uses the average of the two neighboring pixels (left +and above) to predict the value of a pixel. + +To compute the Average filter, apply the following formula to each byte +of each scanline: + + Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2) + +where x ranges from zero to the number of bytes representing that +scanline minus one, Raw(x) refers to the raw data byte at that byte +position in the scanline, Prior(x) refers to the unfiltered bytes of the +prior scanline, and bpp is defined as for the Sub filter. + +Note this is done for each byte, regardless of bit depth. The sequence of +Average values is transmitted as the filtered scanline. + +The subtraction of the predicted value from the raw byte must be done +modulo 256, so that both the inputs and outputs fit into bytes. However, +the sum Raw(x-bpp)+Prior(x) must be formed without overflow +(using at least nine-bit arithmetic). floor() indicates that the result +of the division is rounded to the next lower integer if fractional; in other +words, it is an integer division or right shift operation. + +For all x < 0, assume Raw(x) = 0. On the first scanline of an image (or of +a pass of an interlaced image), assume Prior(x) = 0 for all x. + +To reverse the effect of the Average filter after decompression, output +the following value: + + Average(x) + floor((Raw(x-bpp)+Prior(x))/2) + +where the result is computed mod 256, but the prediction is calculated in +the same way as for encoding. Raw refers to the bytes already decoded, +and Prior refers to the decoded bytes of the prior scanline. + +Filter type 4: Paeth +==================== + +The Paeth filter computes a simple linear function of the three +neighboring pixels (left, above, upper left), then chooses as predictor the +neighboring pixel closest to the computed value. This technique is taken +from Alan W. Paeth's article "Image File Compression Made Easy" in +Graphics Gems II, James Arvo, editor, Academic Press, 1991. + +To compute the Paeth filter, apply the following formula to each byte of +each scanline: + + Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp),Prior(x),Prior(x-bpp)) + +where x ranges from zero to the number of bytes representing that +scanline minus one, Raw(x) refers to the raw data byte at that byte +position in the scanline, Prior(x) refers to the unfiltered bytes of the +prior scanline, and bpp is defined as for the Sub filter. + +Note this is done for each byte, regardless of bit depth. Unsigned +arithmetic modulo 256 is used, so that both the inputs and outputs fit +into bytes. The sequence of Paeth values is transmitted as the filtered +scanline. + +The PaethPredictor function is defined by the following pseudocode: + + function PaethPredictor (a, b, c) + begin + ; a = left, b = above, c = upper left + p := a + b - c ; initial estimate + pa := abs(p - a) ; distances to a, b, c + pb := abs(p - b) + pc := abs(p - c) + ; return nearest of a,b,c, + ; breaking ties in order a,b,c. + if pa <= pb AND pa <= pc + begin + return a + end + if pb <= pc + begin + return b + end + return c + end + +The calculations within the PaethPredictor function must be performed +exactly, without overflow. Arithmetic modulo 256 is to be used only for +the final step of subtracting the function result from the target pixel +value. + +Note that the order in which ties are broken is fixed and must not be +altered. The tie break order is: pixel to the left, pixel above, pixel to the +upper left. (This order differs from that given in Paeth's article.) + +For all x < 0, assume Raw(x) = 0 and Prior(x) = 0. On the first scanline +of an image (or of a pass of an interlaced image), assume Prior(x) = 0 +for all x. + +To reverse the effect of the Paeth filter after decompression, output the +following value: + + Paeth(x) + PaethPredictor(Raw(x-bpp),Prior(x),Prior(x-bpp)) + +(computed mod 256), where Raw and Prior refer to bytes already +decoded. Exactly the same PaethPredictor function is used by both +encoder and decoder. + +For more information, check out the above ftp sites. + +EXTENSION:PNG +OCCURENCES:PC,UNIX,AMIGA +PROGRAMS:???? +REFERENCE:The PNG Specification +--------M-PTM------------------------------- +Poly Tracker is a Scream Tracker 3 like tracker written by Lone Ranger of AcmE. +This is a description of version 2.03 of the PTM format. Early formats are no +longer used or supported by the current version of Poly Tracker (it still says +"version 1.0á", but there have been about a dozen different versions, including +some customized test versions). The samples are stored using delta-compression. + +OFFSET Count TYPE Description +0000h 28 char Songname in ASCIZ format, 0 padded +001Ch 1 char ID=#26 +001Dh 1 word File type version, currently 0203h +001Fh 1 byte reserved (0) +0020h 1 word Number of orders + ="ORD" +0022h 1 word Number of instruments + ="INS" +0024h 1 word Number of patterns + ="PAT" +0026h 1 word Number of voices used + ="CHN" +0028h 1 word File flags (always 0 ??) +002Ah 1 word reserved (0) +002Ch 4 char ID='PTMF' +0030h 16 byte reserved (0) +0040h 32 byte Pan settings for each channel : + 0 = left, 7 = middle, 15 = right +0060h 256 byte Order list, valid entries are 0.."ORD" +0160h 128 word (Pattern offsets) div 16 + +The instruments data follows immediately after the header. +--- PTM instrument format +There are 0.."INS" instruments in the file, each of the following format : +OFFSET Count TYPE Description +0000h 1 byte Sample type (bit mapped) + 0,1 : 0 - no sample (instrument info only) + 1 - normal sample (FileOfs / Length fields are valid) + 2 - OPL2 / OPL3 instrument (not used) + 3 - MIDI instrument (not used) + 2 - sample loop (0 = no loop, 1 = loop) + 3 - loop type (0 = unidirectional, 1 = bidirectional) + 4 - sample resolution (0 = 8 bits, 1 = 16 bits) +0001h 12 char Name of external sample file +000Dh 1 byte Default volume for sample +000Eh 1 word C4 speed +0010h 1 word reserved (0) +0012h 1 dword absolute? offset of sample data +0016h 1 dword Size of sample in bytes +001Ah 1 dword Start of loop +001Eh 1 dword End of loop +0022h 13 byte reserved (0) +0030h 28 char ASCIZ name of sample +004Ch 4 char ID='PTMS' + +EXTENSION:PTM +OCCURENCES:PC +--------M-PS16------------------------------ +The Protracker Studio 16 Modules are yet another digital music format. +The Protracker modules can have up to 255 different patterns and a length of +up to 255 patterns with 31 instruments. The samples can only have a size of +up to 64K, there is a maximum of 16 tracks supported. +The header of each MOD file looks like this : +OFFSET Count TYPE Description +0000h 5 char Header string + ID='PS16',254 +0005h 75 char Song name, ending with ^Z so that if typing + the file will result in PS16 +0050h 1 byte File type : + 0 - Module with patterns and samples + 1 - Song with patterns but without samples +0051h 1 dword Offset of comment field from start of file. + Zero if no commend is stored. +0055h 1 byte Format version byte (0) +0056h 1 byte Number of patterns in the file + ="PAT" +0057h 1 dword Total size of all patterns in bytes, stored + for quick disk reads. +005Bh 1 byte Songlength, number of sequences. +005Ch 128 byte Sequencing information for file +00CCh 31 rec Sample information + 1 byte Sample flags, bitmapped : + 0 - synthesized / digital + 1 - Waveform / FM + (only if bit 0 is set) + 2 - 16 bit / 8 bit + 1 byte Default volume for the sample (0-64) + 1 byte Sample fine tuning (signed nibble) + 1 dword Sample length - Protracker does only support + samples with a size less than 64K. + 1 dword Sample loop start + 1 dword Sample loop length + 1 word Default playback frequency for C2 + Can be used to fine tune a sample. +00CCh+ "PAT" rec The pattern information + 31*17 The tracks are stored sequentially after each + other, first all rows of track 1, then all rows + of track 2 and so on. + 1 word Pattern size+3, rounded up to a paragraph + boundary. + 1 byte Number of rows in pattern + ="ROW" + "ROW" rec + 2 byte Note information, bitmapped : + 0-5 - Note (see table 0005) + 6 - Bit 4 of instrument + 7 - Compression bit + If this bit not set, there is another + byte following the note record + specifying the row where the next + event takes place - if it is set, + the next note follows immediately. + A track is terminated by a 0FFh byte. + 8-11 - Effect bits + 12-15 - Bits 0-3 of instrument + 1 byte Effect data +00CCh+ ? byte Sample data in delta format + 31*17+ See algorthm.txt for details. + ???? + +The comment block contains information about the sample names as well +as some comments to the module. It is formatted like this : +OFFSET Count TYPE Description +0000h 4 char ID='INST' + 1 byte Instrument name length + ="LEN" + 1 byte Sample name count + ="CNT" + "LEN"*"CNT" char Sample names +0000h+ 4 char ID='TEXT' + "LEN"*"CNT"+4 + 1 word Length of following text +EXTENSION:MOD +OCCURENCES:PC +PROGRAMS:Protracker +REFERENCE: +SEE ALSO:DMF,MOD,S3M,STM +VALIDATION: +--------I-QFX------------------------------- +QFX files are yet another graphic file format used to store received +fax images. The .QFX file format is proprietary to Smith Micro Software, Inc. +and is used by the Quick Link II fax software. +The QFX file header is exactly 1536 bytes long. The fax pages themselves +are stored in byte aligned, bit reversed T4 format terminated with 6 EOL's. +See CCITT Recommendation T.4 for full documentation on this coding scheme. + +OFFSET Count TYPE Description +0000h 8 char ID='QLIIFAX',0 +0008h 1 word Number of pages in the QFX file +000Ah 1 word Number of scan lines on last page +000Ch 1 dword Number of scan lines for all pages +0010h 1 word Horizontal scaling + 1 - High res (200x200), + 2 - Normal res (200x100) +0012h 1 word Vertical scaling (always = 1). +0014h 12 byte reserved +0020h 375 dword Offsets of the single pages in the document. + Page 1 always starts at offset 1536. The last + non-zero dword points to the end of the last + page, the first zero dword marks the end of + the pages. +0600h ? byte Start of fax page images + +EXTENSION:QFX +OCCURENCES:PC +PROGRAMS:Quick Link II +--------S-RAW------------------------------- +The RAW files are raw signed PCM sound files. PCM means Pulse Code +Modulation - which can be played through most sound devices without +further manipulation. There is no header or whatsoever. +The properties include 8/16-bit samples in INTEL order, +stereo or mono format. No identification is possible. +EXTENSION:RAW +SEE ALSO:SND +--------I-RDIB------------------------------ +The RDIB files are Device Independent Bitmaps used by Windows. They are RIFF +format files. The blocks are unknown to me. +SEE ALSO:RIFF +--------f-RIFF------------------------------ +The RIFF (Resource interchange file format) format was created by Microsoft and +is used by many applications like Windows, Corel Draw etc.. It is block +structured, each block has a header ID and a size, so that even a program that +works with an old version of the file format can skip the unknown parts of the +file and work on the known parts of the file. All RIFF blocks begin on a word +boundary so it might be necessary to skip an additional byte. In the present +specification, only one RIFF block per file is allowed, and only the RIFF and +LIST blocks may contain subblocks. + +The order of blocks in a RIFF file is not mandatory, so you should always scan +the whole file for the block ID you seek. Throughout this file, the RIFF block +IDs are given in square brackets []. Each ID is always 4 characters dword. + +OFFSET Count TYPE Description +0000h 4 char ID='RIFF' + Each RIFF format file has a header with the + signature and the size of the following + blocks. +0004h 1 dword Block size. This size is the size of the block + controlled by the RIFF header. Normally this + equals the file size. + ="BSZ" +0008h 4 char Format name. This is the format name of the RIFF + file. +After this RIFF header comes the first RIFF record. Each RIFF record has the +following format : +OFFSET Count TYPE Description +0000h 4 char Signature. This is the description of what is + contained in this block. +0004h 1 dword Block size. This is the size of the following + data block. To get the offset of the next RIFF + block record, you have to add this value + 8 to + the offset of the current record. + +---RiffBLOCK [LIST] +This block contains a string list, again in the RIFF subblock format. This list +is used for messages and/or copyright messages. All strings in the LIST block +share the same format, each block contains one ASCIIZ string - the most common +LIST block is the [INFO] block, which can contain the following subblocks : + +[INAM] +The name of the data stored in the file +[ICRD] +Creation date of the file + +SEE ALSO:BMP,rDIB,IFF,WAVe,RIFX +OCCURENCES:PC +PROGRAMS:Windows,Corel Draw +REFERENCE:DDJ0994 +VALIDATION:FileSize="BSZ"+8 +--------f-RIFX-M---------------------------- +The RIFX file format is identical to the RIFF file format except that all values +are in Motorola byte order. +OFFSET Count TYPE Description +0000h 4 char ID='RIFX' +0004h 1 dword Block size. This size is the size of the block + controlled by the RIFX header. + ="BSZ" +0008h 4 char Format name. +REFERENCE:DDJ0994 +SEE ALSO:RIFF +--------S-S3I------------------------------- +This is the Digiplayer/ST3.0 digital sample file format. The sample +files include information about the loop of the instrument. The AdLib +instruments have another format listed below. + +OFFSET Count TYPE Description +0000h 1 byte ID=01h +0001h 12 char DOS filename +000Dh 1 byte reserved (0) +000Eh 1 word Paragraph offset of the raw sample data + from beginning of file. +0010h 1 dword Sample length in bytes +0014h 1 dword Start of sample loop +0018h 1 dword End of sample loop +001Ch 1 byte Playback volumne of sample +001Dh 1 byte ??? "DSK" what ever that means +001Eh 1 byte Pack type + 0 - unpacked + 1 - DP30ADPCM 1 +001Fh 1 byte Flags (bitmapped) + 0 - loop on/off + 1 - stereo sample (length bytes for left channel, + then another length bytes for right channel!) + 2 - 16-Bit samples (in Intel byte order) +0020h 1 dword C2 frequency +0024h 1 dword reserved +0028h 1 word reserved +002Ah 1 word ID=512 +002Ch 1 dword ?? Date of last modification ?? (see table 0009) +0030h 28 char ASCIIZ Sample name +003Ch 4 char ID='SCRS' +0040h ? byte Raw sample data + +Here follows the AdLib instrument format for which I don't know the +extension (yet) : + +OFFSET Count TYPE Description +0000h 1 byte Instrument type + 2 - melodic instrument + 3 - bass drum + 4 - snare drum + 5 - tom tom + 6 - cymbal + 7 - hihat +0001h 12 char DOS file name +000Dh 3 byte reserved +0010h 1 byte Modulator description (bitmapped) + 0-3 - frequency multiplier + 4 - scale envelope + 5 - sustain + 6 - pitch vibrato + 7 - volume vibrato +0011h 1 byte Carrier description (same as modulator) +0012h 1 byte Modulator miscellaneous (bitmapped) + 0-5 - 63-volume + 6 - MSB of levelscale + 7 - LSB of levelscale +0013h 1 byte Carrier description (same as modulator) +0014h 1 byte Modulator attack / decay byte (bitmapped) + 0-3 - Decay + 4-7 - Attack +0015h 1 byte Carrier description (same as modulator) +0016h 1 byte Modulator sustain / release byte (bitmapped) + 0-3 - Release count + 4-7 - 15-Sustain +0017h 1 byte Carrier description (same as modulator) +0018h 1 byte Modulator wave select +0019h 1 byte Carrier wave select +001Ah 1 byte Modulator feedback byte (bitmapped) + 0 - additive synthesis on/off + 1-7 - modulation feedback +001Bh 1 byte reserved +001Ch 1 byte Instrument playback volume +001Dh 1 byte ??? "DSK" +001Eh 1 word reserved +0020h 1 dword C2 frequency +0024h 12 byte reserved +0030h 28 char ASCIIZ Instrument name +004Ch 4 char ID='SCRI' + +EXTENSION:S3I,SMP +OCCURENCES:PC +PROGRAMS:ScreamTracker 3.0 +SEE ALSO:MTM,S3M,STM +--------M-S3M------------------------------- +The ScreamTracker composer and the ScreamTracker Music Interface Kit (STMIK) +were written by the demo group Future Crew for their demonstrations and +released. S3M files are the files of the version 3 of the ScreamTracker. + +OFFSET Count TYPE Description +0000h 20 char Song name, ASCII, 0 padded +001Ch 1 byte ID=1Ah +001Dh 1 byte Filetype : + 16=Module + 17=Song + ? What is this supposed to mean ? +001Eh 1 word Reserved +0020h 1 word Number of orders in song + ="ORD" +0022h 1 word Number of instruments in song + ="INS" +0024h 1 word Number of patterns in song + ="PAT" +0026h 1 word Song flags, bitmapped + 0 - ScreamTracker 2.0 type vibrato + 1 - ScreamTracker 2.0 type tempo + 2 - Amiga type slides + 3 - Zero volume optimizations + 4 - Amiga limits + 5 - enable filters / sfx +0028h 1 word Tracker version +002Ah 1 word File format version + 1=Original format + 2=Original format, unsigned samples +002Ch 4 char ID='SCRM' +0032h 1 byte Maximum volume +0033h 1 byte Initial speed +0034h 1 byte Initial tempo +0035h 1 byte Master multiplier + Whats this ???? +0036h 12 byte reserved +0040h 32 byte Channel balance settings + 0=left + 127=right + +128=disabled + 255=unused +0060h "ORD" byte Ordering sequence of the patterns +0060h "INS" word Offset of the instruments in paragraphs from ++"ORD" begin of header (for binary offset, multiply with 16) +0060h "PAT" word Offset of the pattern data from begin of header ++"ORD" in paragraphs ++"INS"*2 + +EXTENSION:S3M +OCCURENCES:PC +PROGRAMS:ScreamTracker 3.0 +SEE ALSO:S3I,STM,S2M +--------S-SND------------------------------- +The SND files are raw unsigned PCM sound files. PCM means Pulse Code +Modulation - which can be played through most sound devices without +further manipulation. There is no header or whatsoever. +The properties include 8/16-bit samples in INTEL order, +stereo or mono format. No identification is possible. +EXTENSION:SND +SEE ALSO:RAW +--------A-SQZ------------------------------- +The SQZ files are yet another archive format. The SQZ archives consist of one +archive header and several file headers. The archive header has the +following format : +OFFSET Count TYPE Description +0000h 5 char ID='HLSQZ' +0005h 1 char Version in ASCII + ID='1' +0006h 1 byte OS byte, + 0 - PC-DOS / MS-DOS + 1 - OS/2 + 2 - MVS + 3 - HPFS (OS/2) + 4 - Amiga + 5 - Macintosh + 6 - Unix +0007h 1 byte Misc. flags, bitmapped : + 0 - Intel byte order / Motorola byte order + 1 - Filetime in ?? / File time in DOS format + 2 - No security envelope / security envelope + 3-7 - reserved + +After the header and each block, there is one byte denoting the type/size of the +next block : +OFFSET Count TYPE Description +0000h 1 byte Block/size specifier : + 0 - End of archive + 1 - Comment + 2 - Password + 3 - Security envelope + 4-18 - reserved + >18 - normal file header, + byte value is size of header + +The normal file header then has the following format : +OFFSET Count TYPE Description +0000h 1 byte Checksum of header +0001h 1 byte Flags, bitmapped : + 0-3 : Compression method : + 0 - + 1 - + 2 - + 3 - + 4 - + 4 - Security envelope should follow + 5-7 - reserved +0002h 1 dword Compressed size of file +0006h 1 dword Original file size +000Ah 1 dword Date and time of file (see table 0009) +000Eh 1 byte File attributes +000Fh 1 dword CRC-32 of file +0013h ? char Filename (see above for length) + +The comment block : +OFFSET Count TYPE Description +0000h 1 word Size of uncompressed comment +0002h 1 word Size of compressed comment data + ="LEN" +0004h 1 byte Flags, bitmapped, see above +0005h 1 dword CRC-32 +0009h "LEN" byte Compressed comment data + +The password block : +OFFSET Count TYPE Description +0000h 1 word Size of password block (=4) +0004h 1 dword CRC-32 of password + +Other blocks : +OFFSET Count TYPE Description +0000h 1 word Size of this block + ="LEN" +0002h "LEN" byte Block data + +EXTENSION:SQZ +OCCURENCES:PC +PROGRAMS:?? +REFERENCE: +SEE ALSO: +--------S-SDK------------------------------- +The SDK files are disk images from disks used by the Roland +S-550/S-50/S-330 sampler devices. +Further information wanted. +EXTENSION:SDK +--------S-SDS------------------------------- +The SDS files are MIDI Sample Dump Standart files and are used +to transfer samples between MIDI devices. +Further information wanted. +EXTENSION:SDS +SEE ALSO:MID,SDX +--------S-SDX------------------------------- +The SDX file are like the SDS files sample dump files used +for transfer of data between MIDI devices. +EXTENSION:SDX +SEE ALSO:MID,SDS +--------S-SMP------------------------------- +The SMP files are digital sample files used by Samplevision software. +Further information wanted. +EXTENSION:SMP +--------M-STM------------------------------- +The ScreamTracker 1.0 format was the module format used by the +ScreamTracker before version 2.0. + +OFFSET Count TYPE Description +0000h 20 char ASCIIZ song name +0014h 8 char Tracker name +001Ch 1 byte ID=1Ah +001Dh 1 byte File type + 1 - song (contains no samples) + 2 - module (contains samples) +001Eh 1 byte Major version number +001Fh 1 byte Minor version number +0020h 1 byte Playback tempo +0021h 1 byte Number of patterns + ="PAT" +0022h 1 byte Global playback volume +0023h 13 byte reserved +0030h 31 rec Instrument data + 12 char ASCIIZ instrument name + 1 byte ID=0 + 1 byte Instrument disk + 1 word reserved + 1 word Sample length in bytes + 1 word Sample loop start + 1 word Sample loop end + 1 byte Sample playback volume + 1 byte reserved + 1 word C3 frequency in Hz + 1 dword reserved + 1 word length in paragraphs + (only for modules,in songs:reserved) +03D0h 64 byte Pattern orders +0410h 4*64*"PAT" rec Pattern data. Each pattern consists of + 64 rows, each 4 channels. The channels + are stored from left ro right, row by row. + 1 byte Note byte : + 251 - last 3 bytes not stored, all bytes 0 + 252 - last 3 bytes not stored, note -0-, + whatever that means. + 253 - last 3 bytes not stored, note ... + 254 - undefined (reserved for run-time) + 255 - undefined (reserved for run-time) + otherwise bit mapped : + 0-3 : note (c=0,c#=1...) + 4-7 : octave + 1 byte Only valid if above byte < 251, bit mapped + 0-2 ; lower bit of note volume + 3-7 : instrument number + 1 byte bit mapped + 0-3 : Effect command in ProTracker format + seems to be overlapped by volume + bits... + 4-6 : upper bits of volume + 1 byte command data in ProTracker format +0410h+ ? byte Raw sample data padded to 16 byte boundaries. + 4*64*4*"PAT" + +EXTENSION:STM +OCCURENCES:PC +PROGRAMS:ScreamTracker 1.0 +REFERENCE: +SEE ALSO:S3M,MOD +--------A-TAR-G----------------------------- +The Unix Tape ARchives mostly have the extension TAR. The info about this +comes from a magic file, thus useful only for identification. +--------A-TAR------------------------------- +The Unix TAR program is an archiver program which stores files in a single +archive without compression. +OFFSET Count TYPE Description +@section The Standard Format +A @dfn{tar tape} or file contains a series of records. Each record +contains @code{RECORDSIZE} 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 record which describes +the file, followed by zero or more records which give the contents +of the file. At the end of the archive file there may be a record +filled with binary zeros as an end-of-file marker. A reasonable +system should write a record of zeros at the end, but must not +assume that such a record exists when reading an archive. + +The records may be @dfn{blocked} for physical I/O operations. Each +block of @var{N} records (where @var{N} is set by the @samp{-b} +option to @code{tar}) is written with a single @code{write()} +operation. On magnetic tapes, the result of such a write is a +single tape record. When writing an archive, the last block of +records should be written at the full size, with records after the +zero record containing all zeroes. When reading an archive, a +reasonable system should properly handle an archive whose last block +is shorter than the rest, or which contains garbage records after a +zero record. + +The header record is defined in C as follows: + +@example +/* + * Standard Archive Format - Standard TAR - USTAR + */ +#define RECORDSIZE 512 +#define NAMSIZ 100 +#define TUNMLEN 32 +#define TGNMLEN 32 + +union record @{ + char charptr[RECORDSIZE]; + struct header @{ + char name[NAMSIZ]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char linkflag; + char linkname[NAMSIZ]; + char magic[8]; + char uname[TUNMLEN]; + char gname[TGNMLEN]; + char devmajor[8]; + char devminor[8]; + @} header; +@}; + +/* The checksum field is filled with this while the checksum is computed. */ +#define CHKBLANKS " " /* 8 blanks, no null */ + +/* The magic field is filled with this if uname and gname are valid. */ +#define TMAGIC "ustar " /* 7 chars and a null */ + +/* The magic field is filled with this if this is a GNU format dump entry */ +#define GNUMAGIC "GNUtar " /* 7 chars and a null */ + +/* The linkflag defines the type of file */ +#define LF_OLDNORMAL '\0' /* Normal disk file, Unix compatible */ +#define LF_NORMAL '0' /* Normal disk file */ +#define LF_LINK '1' /* Link to previously dumped file */ +#define LF_SYMLINK '2' /* Symbolic link */ +#define LF_CHR '3' /* Character special file */ +#define LF_BLK '4' /* Block special file */ +#define LF_DIR '5' /* Directory */ +#define LF_FIFO '6' /* FIFO special file */ +#define LF_CONTIG '7' /* Contiguous file */ + +/* Further link types may be defined later. */ + +/* Bits used in the mode field - values in octal */ +#define TSUID 04000 /* Set UID on execution */ +#define TSGID 02000 /* Set GID on execution */ +#define TSVTX 01000 /* Save text (sticky bit) */ + +/* File permissions */ +#define TUREAD 00400 /* read by owner */ +#define TUWRITE 00200 /* write by owner */ +#define TUEXEC 00100 /* execute/search by owner */ +#define TGREAD 00040 /* read by group */ +#define TGWRITE 00020 /* write by group */ +#define TGEXEC 00010 /* execute/search by group */ +#define TOREAD 00004 /* read by other */ +#define TOWRITE 00002 /* write by other */ +#define TOEXEC 00001 /* execute/search by other */ +@end example + +All characters in header records are represented by using 8-bit +characters in the local variant of ASCII. Each field within the +structure is contiguous; that is, there is no padding used within +the structure. Each character on the archive medium is stored +contiguously. + +Bytes representing the contents of files (after the header record of +each file) are not translated in any way and are not constrained to +represent characters in any character set. The @code{tar} format +does not distinguish text files from binary files, and no +translation of file contents is performed. + +The @code{name}, @code{linkname}, @code{magic}, @code{uname}, and +@code{gname} are null-terminated character strings. All other +fileds are zero-filled octal numbers in ASCII. Each numeric field +of width @var{w} contains @var{w}@minus{} 2 digits, a space, and a null, +except @code{size}, and @code{mtime}, which do not contain the +trailing null. + +The @code{name} field is the pathname of the file, with directory +names (if any) preceding the file name, separated by slashes. + +The @code{mode} field provides nine bits specifying file permissions +and three bits to specify the Set UID, Set GID, and Save Text +(``stick'') modes. Values for these bits are defined above. When +special permissions are required to create a file with a given mode, +and the user restoring files from the archive does not hold such +permissions, the mode bit(s) specifying those special permissions +are ignored. Modes which are not supported by the operating system +restoring files from the archive will be ignored. Unsupported modes +should be faked up when creating or updating an archive; e.g. the +group permission could be copied from the @code{other} permission. + +The @code{uid} and @code{gid} fields are the numeric user and group +ID of the file owners, respectively. If the operating system does +not support numeric user or group IDs, these fields should be +ignored. + +The @code{size} field is the size of the file in bytes; linked files +are archived with this field specified as zero. +@xref{Extraction Options}; in particular the @samp{-G} option.@refill + +The @code{mtime} field is the modification time of the file at the +time it was archived. It is the ASCII representation of the octal +value of the last time the file was modified, represented as an +integer number of seconds since January 1, 1970, 00:00 Coordinated +Universal Time. + +The @code{chksum} field is the ASCII representation of the octal +value of the simple sum of all bytes in the header record. Each +8-bit byte in the header is added to an unsigned integer, +initialized to zero, the precision of which shall be no less than +seventeen bits. When calculating the checksum, the @code{chksum} +field is treated as if it were all blanks. + +The @code{typeflag} field specifies the type of file archived. If a +particular implementation does not recognize or permit the specified +type, the file will be extracted as if it were a regular file. As +this action occurs, @code{tar} issues a warning to the standard +error. + +@table @code +@item LF_NORMAL +@itemx LF_OLDNORMAL +These represent a regular file. In order to be compatible with +older versions of @code{tar}, a @code{typeflag} value of +@code{LF_OLDNORMAL} should be silently recognized as a regular +file. New archives should be created using @code{LF_NORMAL}. Also, +for backward compatibility, @code{tar} treats a regular file whose +name ends with a slash as a directory. + +@item LF_LINK +This represents a file linked to another file, of any type, +previously archived. Such files are identified in Unix by each file +having the same device and inode number. The linked-to +name is specified in the @code{linkname} field with a trailing null. + +@item LF_SYMLINK +This represents a symbolic link to another file. The linked-to +name is specified in the @code{linkname} field with a trailing null. + +@item LF_CHR +@itemx LF_BLK +These represent character special files and block special files +respectively. In this case the @code{devmajor} and @code{devminor} +fields will contain the major and minor device numbers +respectively. Operating systems may map the device specifications +to their own local specification, or may ignore the entry. + +@item LF_DIR +This specifies a directory or sub-directory. The directory name in +the @code{name} field should end with a slash. On systems where +disk allocation is performed on a directory basis the @code{size} +field will contain the maximum number of bytes (which may be rounded +to the nearest disk block allocation unit) which the directory may +hold. A @code{size} field of zero indicates no such limiting. +Systems which do not support limiting in this manner should ignore +the @code{size} field. + +@item LF_FIFO +This specifies a FIFO special file. Note that the archiving of a +FIFO file archives the existence of this file and not its contents. + +@item LF_CONTIG +This specifies a contiguous file, which is the same as a normal +file except that, in operating systems which support it, +all its space is allocated contiguously on the disk. Operating +systems which do not allow contiguous allocation should silently treat +this type as a normal file. + +@item 'A' @dots{} +@itemx 'Z' +These are reserved for custom implementations. Some of these are +used in the GNU modified format, as described below. +@end table + +Other values are reserved for specification in future revisions of +the P1003 standard, and should not be used by any @code{tar} program. + +The @code{magic} field indicates that this archive was output in the +P1003 archive format. If this field contains @code{TMAGIC}, the +@code{uname} and @code{gname} fields will contain the ASCII +representation of the owner and group of the file respectively. If +found, the user and group ID represented by these names will be used +rather than the values within the @code{uid} and @code{gid} fields. + +@section GNU Extensions to the Archive Format +The GNU format uses additional file types to describe new types of +files in an archive. These are listed below. + +@table @code +@item LF_DUMPDIR +@itemx 'D' +This represents a directory and a list of files created by the +@samp{-G} option. The @code{size} field gives the total size of the +associated list of files. Each filename is preceded by either a @code{'Y'} +(the file should be in this archive) or an @code{'N'} (The file is a +directory, or is not stored in the archive). Each filename is +terminated by a null. There is an additional null after the last +filename. + +@item LF_MULTIVOL +@itemx 'M' +This represents a file continued from another volume of a +multi-volume archive created with the @samp{-M} option. The original +type of the file is not given here. The @code{size} field gives the +maximum size of this piece of the file (assuming the volume does not +end before the file is written out). The @code{offset} field gives +the offset from the beginning of the file where this part of the +file begins. Thus @code{size} plus @code{offset} should equal the +original size of the file. + +@item LF_VOLHDR +@itemx 'V' +This file type is used to mark the volume header that was given with +the @samp{-V} option when the archive was created. The @code{name} +field contains the @code{name} given after the @samp{-V} option. +The @code{size} field is zero. Only the first file in each volume +of an archive should have this type. + +@end table +EXTENSION: +OCCURENCES: +PROGRAMS: +REFERENCE: +SEE ALSO: +VALIDATION: +OFFSET Count TYPE Description +0000h 256 byte Other header info ? +0100h 6 char ID='ustar',0 +EXTENSION:TAR +OCCURENCES:PC, Unix +PROGRAMS:TAR +--------G-TDDD------------------------------ +This format is used by the Imagine rendering package. The names of the blocks +are unknown to me. +OFFSET Count TYPE Description +EXTENSION:IFF +OCCURENCES:Amiga,PC +PROGRAMS:Imagine package +REFERENCE:DDJ0794 +SEE ALSO:IFF +--------I-TIFF------------------------------ +The TIFF file format was designed jointly by Aldus and Microsoft with leading +scanner vendors to faciliate incorporating scanned images into publishing. +The described TIFF specification is TIFF 5.0. A TIFF file consists of several +different blocks which define the palette data or the LZW-compressed body +among other things. TIFF files can be in Motorola _or_ Intel byte order, +depending on the first word. If it is 'II', the byte order is in Intel order, +if it is 'MM', then you have Motorola byte ordering. + +Each TIFF file begins with a image file header which points to one or more image +file directories, which contain the image data and image information. + +The format of the image header : +OFFSET Count TYPE Description +0000h 2 char ID='II', ID='MM' + This is the identification, 'II' stands for + Intel byte order, 'MM' for Motorola byte + order. The following data must be interpreted + accordingly ! +0002h 1 word TIFF "version number". This version number + never changed and the value (42) was choosen + for its deep philosophical value. In fact, if + the version number ever changes, this means + that radical changes to the TIFF format have + been made, and a TIFF reader should give up + immediately. + You can consider this word to be a part of the + header ID. +0004h 1 dword Offset of first image directory in file form + start of file. + The first image directory must begin on an + even byte boundary. The image directory may + follow the image data it describes. The + image directory is described below. + +An organization may wish to store information that is meaningful to only that +organization in a TIFF file. Tags numbered 32768 or higher are reserved for +that purpose. Upon request, the administrator will allocate and register a block +of private tags for an organization. +Private enumerated values can be accommodated in a similar fashion. + +The format of the image file directory (IFD) : +All entries are sorted in ascending order by the tag field. +OFFSET Count TYPE Description +0000h 1 word Number of entries + ="NUM" +0002h "NUM" rec Field descriptor + 1 word Field tag, see below + 1 word Field type + 1 - byte + 2 - ASCII string, counted in length. + Most often an ASCIIZ string, the + trailing zero is counted with the + data length. + 3 - word + 4 - dword / uword + 5 - rational (2 dwords, numerator and denominator) + 1 dword Length of the field in units of the data type. + A single 16-bit word has the length 1. + 1 dword Data offset of the field. The data starts + on a word boundary, thus the dword should + be even. The data for the field may be + anywhere in the file, even after the image + data. If the data size is less or equal to + 4 bytes (determined by the field type and + length), then this offset is not a offset + but instead the data itself, to save space. + If the data size is less than 4 bytes, the + data is stored left-justified within the 4 + bytes of the offset field. +0002h+ + "NUM"*12 1 dword Offset of next IFD in file, 0 if none follow + +If a certain field in the IFD does not exist, you have to presume the default +values. The different fields are : + +--- BitsPerSample +Tag = 258 (102) +Type = word +N = SamplesPerPixel +Default = 1 + +Number of bits per sample. Note that this tag allows a different number of +bits per sample for each sample corresponding to a pixel. For example, RGB +color data could use a different number of bits per sample for each of the +three color planes. + +--- ColorMap +Tag = 320 (140) +Type = word +N = 3 * (2**BitsPerSample) +No default.ColorMap must be included in all palette color images. + +This tag defines a Red-Green-Blue color map for palette color images. +The palette color pixel value is used to index into all 3 subcurves. +The subcurves are stored sequentially. The Red entries come first, followed +by the Green entries, followed by the Blue entries. +The width of each entry is 16 bits, as implied by the type of word. +0 represents the minimum intensity, and 65535 represents the maximum intensity. + +--- ColorResponseCurves +Tag = 301 (12D) +Type = word +N = 3 * (2**BitsPerSample) +Default: curves based on the NTSC recommended gamma of 2.2. + +This tag defines three color response curves, one each for Red, Green and Blue +color information. The Red entries come first, followed by the Green entries, +followed by the Blue entries. The length of each subcurve is 2**BitsPerSample, +using the BitsPerSample value corresponding to the respective primary. The width +of each entry is 16 bits, as implied by the type of word. +The purpose of the color response curves is to refine the content of RGB color images. + +--- Compression +Tag = 259 (103) +Type = word +N = 1 +Default = 1. + +1 = No compression, but pack data into bytes as tightly as possible, with no + unused bits except at the end of a row. The bytes are stored as an array + of bytes, for BitsPerSample <= 8, word if BitsPerSample > 8 and <= 16, and + dword if BitsPerSample > 16 and <= 32. The byte ordering of data >8 bits + must be consistent with that specified in the TIFF file header (bytes 0 + and 1). Rows are required to begin on byte boundaries. + +2 = CCITT Group 3 1-Dimensional Modified Huffman run length encoding. + See ALGRTHMS.txt BitsPerSample must be 1, since this type of compression + is defined only for bilevel images (like FAX images...) + +3 = Facsimile-compatible CCITT Group 3, exactly as specified in + "Standardization of Group 3 facsimile apparatus for document + transmission," Recommendation T.4, Volume VII, Fascicle VII.3, + Terminal Equipment and Protocols for Telematic Services, The + International Telegraph and Telephone Consultative Committee + (CCITT), Geneva, 1985, pages 16 through 31. Each strip must + begin on a byte boundary. (But recall that an image can be a + single strip.) Rows that are not the first row of a strip are + not required to begin on a byte boundary. The data is stored as + bytes, not words - byte-reversal is not allowed. See the + Group3Options field for Group 3 options such as 1D vs 2D coding. + +4 = Facsimile-compatible CCITT Group 4, exactly as specified in + "Facsimile Coding Schemes and Coding Control Functions for Group + 4 Facsimile Apparatus," Recommendation T.6, Volume VII, Fascicle + VII.3, Terminal Equipment and Protocols for Telematic Services, + The International Telegraph and Telephone Consultative Committee + (CCITT), Geneva, 1985, pages 40 through 48. Each strip must + begin on a byte boundary. Rows that are not the first row of a + strip are not required to begin on a byte boundary. The data is + stored as bytes, not words. See the Group4Options field for + Group 4 options. + +5 = LZW Compression, for grayscale, mapped color, and full color images. + See ALGRTHMS.txt + +32773 = PackBits compression, a simple byte oriented run length scheme for + 1-bit images. See Appendix C. + + Data compression only applies to raster image data, as pointed to + by StripOffsets. + +--- GrayResponseCurve +Tag = 291 (123) +Type = word +N = 2**BitsPerSample + +The purpose of the gray response curve and the gray units is to +provide more exact photometric interpretation information for +gray scale image data, in terms of optical density. + +--- GrayResponseUnit +Tag = 290 (122) +Type = word +N = 1 +For historical reasons, the default is 2. However, for greater +accuracy, 3 is recommended. + + 1 = Number represents tenths of a unit. + 2 = Number represents hundredths of a unit. + 3 = Number represents thousandths of a unit. + 4 = Number represents ten-thousandths of a unit. + 5 = Number represents hundred-thousandths of a unit. + +--- ImageLength +Tag = 257 (101) +Type = word or dword +N = 1 +No default. + +The image's length (height) in pixels (Y:vertical). The number of rows +(sometimes described as "scan lines") in the image. + +--- ImageWidth +Tag = 256 (100) +Type = word or dword +N = 1 +No default. + +The image's width, in pixels (X:horizontal). The number of columns in the image. + +--- NewSubfileType +Tag = 254 (FE) +Type = dword +N = 1 +Default is 0. + +A general indication of the kind of data that is contained in +this subfile. This field is made up of a set of 32 flag bits. +Unused bits are expected to be 0. Bit 0 is the low-order bit. + + Currently defined values for the bitmap are: + 0 - Image is reduced of another TIFF image in this file + 1 - Image is a single page of a multi-page + 2 - Image is a transparency mask for another image in this file + +--- PhotometricInterpretation +Tag = 262 (106) +Type = word +N = 1 +No default. + +0 = For bilevel and grayscale images: 0 is imaged as white. + 2**BitsPerSample-1 is imaged as black. If GrayResponseCurve + exists, it overrides the PhotometricInterpretation value. + +1 = For bilevel and grayscale images: 0 is imaged as black. + 2**BitsPerSample-1 is imaged as white. If GrayResponseCurve + exists, it overrides the PhotometricInterpretation value. + +2 = RGB. In the RGB model, a color is described as a combination + of the three primary colors of light (red, green, and blue) in + particular concentrations. For each of the three samples, 0 + represents minimum intensity, and 2**BitsPerSample - 1 represents + maximum intensity. For PlanarConfiguration = 1, the samples are stored in + the indicated order: first Red, then Green, then Blue. For + PlanarConfiguration = 2, the StripOffsets for the sample planes + are stored in the indicated order: first the Red sample plane + StripOffsets, then the Green plane StripOffsets, then the Blue + plane StripOffsets. + +3 = "Palette color." In this mode, a color is described with a + single sample. The sample is used as an index into ColorMap. + The sample is used to index into each of the red, green and blue + curve tables to retrieve an RGB triplet defining an actual color. + When this PhotometricInterpretation value is used, the color + response curves must also be supplied. SamplesPerPixel must be + 1. + +4 = Transparency Mask. This means that the image is used to + define an irregularly shaped region of another image in the same + TIFF file. SamplesPerPixel and BitsPerSample must be 1. + PackBits compression is recommended. The 1-bits define the + interior of the region; the 0-bits define the exterior of the + region. The Transparency Mask must have the same ImageLength and + ImageWidth as the main image. + +PlanarConfiguration +Tag = 284 (11C) +Type = word +N = 1 +Default is 1. + +1 = The sample values for each pixel are stored contiguously, so + that there is a single image plane. See PhotometricInterpretation + to determine the order of the samples within the pixel data. So, for + RGB data, the data is stored RGBRGBRGB...and so on. + +2 = The samples are stored in separate "sample planes." The + values in StripOffsets and StripByteCounts are then arranged as a + 2-dimensional array, with SamplesPerPixel rows and StripsPerImage + columns. (All of the columns for row 0 are stored first, + followed by the columns of row 1, and so on.) + PhotometricInterpretation describes the type of data that is + stored in each sample plane. For example, RGB data is stored + with the Red samples in one sample plane, the Green in another, + and the Blue in another. + + If SamplesPerPixel is 1, PlanarConfiguration is irrelevant, and + should not be included. + +Predictor +Tag = 317 (13D) +Type = word +N = 1 +Default is 1. + +To be used when Compression=5 (LZW). + +1 = No prediction scheme used before coding. +2 = Horizontal differencing. See Appendix I. + +ResolutionUnit +Tag = 296 (128) +Type = word +N = 1 +Default is 2. + +To be used with XResolution and YResolution. + +1 = No absolute unit of measurement. Used for images that may + have a non-square aspect ratio, but no meaningful absolute + dimensions. The drawback of ResolutionUnit=1 is that different + applications will import the image at different sizes. Even if + the decision is quite arbitrary, it might be better to use dots + per inch or dots per centimeter, and pick XResolution and + YResolution such that the aspect ratio is correct and the maximum + dimension of the image is about four inches (the "four" is quite + arbitrary.) +2 = Inch. +3 = Centimeter. + +RowsPerStrip +Tag = 278 (116) +Type = word or dword +N = 1 +Default is 2**32 - 1, which is effectively infinity. That is, +the entire image is one strip. Recomended is a strip size of 8K. + +The number of rows per strip. The image data is organized into +strips for fast access to individual rows when the data is +compressed - though this field is valid even if the data is not +compressed. + +--- SamplesPerPixel +Tag = 277 (115) +Type = word +N = 1 +Default = 1. + +The number of samples per pixel. SamplesPerPixel is 1 for +bilevel, grayscale, and palette color images. SamplesPerPixel is +3 for RGB images. + +--- StripByteCounts +Tag = 279 (117) +Type = word or dword +N = StripsPerImage for PlanarConfiguration equal to 1. + = SamplesPerPixel * StripsPerImage for PlanarConfiguration equal to 2 +No default. + +For each strip, the number of bytes in that strip. The existence +of this field greatly simplifies the chore of buffering +compressed data, if the strip size is reasonable. + +--- StripOffsets +Tag = 273 (111) +Type = word or dword +N = StripsPerImage for PlanarConfiguration equal to 1. + = SamplesPerPixel * StripsPerImage for PlanarConfiguration equal to 2 +No default. + +For each strip, the byte offset of that strip. The offset is +specified with respect to the beginning of the TIFF file. Note +that this implies that each strip has a location independent of +the locations of other strips. This feature may be useful for +editing applications. This field is the only way for a reader to +find the image data, and hence must exist. + +--- XResolution +Tag = 282 (11A) +Type = RATIONAL +N = 1 +No default. + +The number of pixels per ResolutionUnit in the X direction, i.e., +in the ImageWidth direction. + + +--- YResolution +Tag = 283 (11B) +Type = RATIONAL +N = 1 +No default. + +The number of pixels per ResolutionUnit in the Y direction, i.e., +in the ImageLength direction. + +--- Artist +Tag = 315 (13B) +Type = ASCII + +Person who created the image. Copyright notice. + +--- DateTime +Tag = 306 (132) +Type = ASCII +N = 20 + +Date and time of image creation. Uses the format "YYYY:MM:DD HH:MM:SS", with +hours on a 24-hour clock, and one space character between the date and the time. +The length of the string, including the null, is 20 bytes. + +--- HostComputer +Tag = 316 (13C) +Type = ASCII + +"ENIAC", or whatever. + +--- ImageDescription +Tag = 270 (10E) +Type = ASCII + +For example, a user may wish to attach a comment such as "1988 company +picnic" to an image. + +--- Make +Tag = 271 (10F) +Type = ASCII + +Manufacturer of the scanner, video digitizer, or whatever. + +--- Model +Tag = 272 (110) +Type = ASCII + +The model name/number of the scanner, video digitizer, or whatever. +This tag is intended for user information only so format is arbitrary. + +--- Software +Tag = 305 (131) +Type = ASCII + +Name and release number of the software package that created the image. +User information only. + +--- Group3Options +Tag = 292 (124) +Type = dword +N = 1 + +Those options are for fax-images stored in TIFF format. +This field is made up of a set of 32 flag bits. Unused bits are expected +to be 0. It is probably not safe to try to read the file if any bit of this +field is set that you don't know the meaning of. + + Bit map : + 0 - 2-dimensional coding used. + 1 - Image is uncompressed + 2 - Fill bits have been added before EOL codes, so that EOL always ends on a + byte boundary. + +--- Group4Options +Tag = 293 (125) +Type = dword +N = 1 + +This field is made up of a set of 32 flag bits and is used for the images +with fax group 4 compression. Unused bits are expected to be 0. It is +probably not safe to try to read the file if any bit of this field is set +that you don't know the meaning of. Gray scale and color coding schemes are +under study, and will be added when finalized. + +For 2-D coding, each strip is encoded as if it were a separate image. In +particular, each strip begins on a byte boundary; and the coding for the +first row of a strip is encoded independently of the previous row, using +horizontal codes, as if the previous row is entirely white. Each strip ends +with the 24-bit end-of-facsimile block (EOFB). + +Bit map : + 0 - reserved (unused) + 1 - uncompressed mode is used + 2-31 - reserved + +--- DocumentName +Tag = 269 (10D) +Type = ASCII + +The name of the document from which this image was scanned. + +--- PageName +Tag = 285 (11D) +Type = ASCII + +The name of the page from which this image was scanned. + +--- PageNumber +Tag = 297 (129) +Type = word +N = 2 + +This tag is used to specify page numbers of a multiple page (e.g. facsimile) +document. Two word values are specified. The first value is the page number; +the second value is the total number of pages in the document. Note that pages +need not appear in numerical order. The first page is 0 (zero). + +--- XPosition +Tag = 286 (11E) +Type = RATIONAL + +The X offset of the left side of the image, with respect to the left side of the +page, in ResolutionUnits. + +--- YPosition +Tag = 287 (11F) +Type = RATIONAL + +The Y offset of the top of the image, with respect to the top of the page, in +ResolutionUnits. In the TIFF coordinate scheme, the positive Y direction is down, +so that YPosition is always positive. + +--- White Point +Tag = 318 (13E) +Type = RATIONAL +N = 2 +Default is the SMPTE white point, D65: x = 0.313, y = 0.329. + +The white point of the image. Note that this value is described using the 1931 +CIE xyY chromaticity diagram and only the chromaticity is specified. The +luminance component is arbitrary and not specified. This can correspond to the +white point of a monitor that the image was painted on, the filter set/light +source combination of a scanner, or to the white point of the illumination model +of a rendering package. The ordering is x, y. + + +--- PrimaryChromaticities +Tag = 319 (13F) +Type = RATIONAL +N = 6 +Default is the SMPTE primary color chromaticities: + + Red: x = 0.635 y = 0.340 + Green: x = 0.305 y = 0.595 + Blue: x = 0.155 y = 0.070 + +The primary color chromaticities. Note that these values are described using +the 1931 CIE xyY chromaticity diagram and only the chromaticities are +specified.For paint images, these represent the chromaticities of the monitor +and for scanned images they are derived from the filter set/light source +combination of a scanner. +The ordering is red x, red y, green x, green y, blue x, blue y. + +--- SubfileType +Tag = 255 (FF) +Type = word +N = 1 + +A general indication of the kind of data that is contained in this subfile. +Currently defined values are: + +1 = full resolution image data - ImageWidth, ImageLength, and StripOffsets are + required fields +2 = reduced resolution image data - ImageWidth, ImageLength, and StripOffsets are + required fields. It is further assumed that a reduced resolution image is a + reduced version of the entire extent of the corresponding full resolution + data. +3 = single page of a multi-page image (see the PageNumber tag description). + +Continued use of this field is not recommended. Writers should instead use the +new and more general NewSubfileType field. + +--- Orientation +Tag = 274 (112) +Type = word +N = 1 +Default is 1. + +1 = The 0th row represents the visual top of the image, and the 0th column + represents the visual left hand side. +2 = The 0th row represents the visual top of the image, and the 0th column + represents the visual right hand side. +3 = The 0th row represents the visual bottom of the image, and the 0th column + represents the visual right hand side. +4 = The 0th row represents the visual bottom of the image, and the 0th column + represents the visual left hand side. +5 = The 0th row represents the visual left hand side of the image, and the 0th + column represents the visual top. +6 = The 0th row represents the visual right hand side of the image, and the 0th + column represents the visual top. +7 = The 0th row represents the visual right hand side of the image, and the 0th + column represents the visual bottom. +8 = The 0th row represents the visual left hand side of the image, and the 0th + column represents the visual bottom. + +It is extremely costly for most readers to perform image rotation "on the fly", + i.e., when importing and printing; and users of most desktop publishing +applications do not expect a file imported by the application to be altered +permanently in any way. + +Threshholding +Tag = 263 (107) +Type = word +N = 1 + +1 = a bilevel "line art" scan. BitsPerSample must be 1. +2 = a "dithered" scan, usually of continuous tone data such as photographs. + BitsPerSample must be 1. +3 = Error Diffused. + +ColorImageType +Tag = 318 (13E) +Type = word +N = 1 +Default is 1. + +Gives TIFF color image readers a better idea of what kind of color image it is. There will be borderline cases. + +1 = Continuous tone, natural image. +2 = Synthetic image, using a greatly restricted range of colors. + Such images are produced by most color paint programs. See ColorList for + a list of colors used in this image. + +ColorList +Tag = 319 (13F) +Type = BYTE or word +N = the number of colors that are used in this image, times SamplesPerPixel + +A list of colors that are used in this image. Use of this field is only +practical for images containing a greatly restricted (usually less than or equal +to 256) range of colors. ColorImageType should be 2. See ColorImageType. + +The list is organized as an array of RGB triplets, with no pad. The RGB triplets +are not guaranteed to be in any particular order. Note that the red, green, and +blue components can either be a BYTE or a word in length. BYTE should be +sufficient for most applications. + +EXTENSION:TIF,TIFF +OCCURENCES:PC,MAC,UNIX +PROGRAMS:Aldus Pagemaker, Paintbrush +REFERENCE: +SEE ALSO: +VALIDATION: +--------I-TARGA----------------------------- +The Targa-File format is an image file format used by a wide variety of both +scanners and imaging software, and exists in many incarnations. The information +has been taken from Appendix C of the Truevision Technical Guide.Requests for +further information could be directed to: + + AT&T + Electronic Photography and Imaging Center + 2002 Wellesley Ave. + Indianapolis, IN 42619 + +The lack of completeness is due to the fact that the Targa recognizes +over half a dozen image file formats, some of which are more widely +used than others. + + +OFFSET Count TYPE Description +0000h 1 byte Length of image identification field (below) +0001h 1 byte Color map type : + 0 - no color map + 1 - 256 entry palette +0002h 1 byte Image type : + 0 - no image data included + 1 - Uncompressed, color-mapped image + 2 - Uncompressed, RGB image + 3 - Uncompressed, black and white image + 9 - RLE encoded color-mapped image + 10 - RLE encoded RGB image + 11 - Compressed, black and white image + 32 - Compressed color-mapped data, using + Huffman, Delta, and runlength encoding. + 33 - Compressed color-mapped data, using + Huffman, Delta, and RLE. 4-pass quadtree- + type process. +0003h 1 word Index of first color map entry +0005h 1 word Count of color map entries +0007h 1 byte Number of bits per color map entry +0008h 1 word X coordinate of the lower left corner of + the image. +000Ah 1 word Y coordinate of the lower left corner of + the image. +000Ch 1 word Width of the image in pixels +000Eh 1 word Height of the image in pixels +0010h 1 byte Bytes per pixel +0011h 1 byte Flags (bitmapped): + 0-3 : Number of attribute bits + 4 : reserved + 5 : Screen origin in upper left corner + 6-7 : Data storage interleave + 00 - no interleave + 01 - even/odd interleave + 10 - four way interleave + 11 - reserved + The byte should be set to 0. Don't know why. +0012h ? char Image identification string, usually not there, + when the length (see up) is 0. +????h ? byte Color map data + Depending on the number of bits per color map + entry, the entries here have a different size. + 4 bytes : 1 byte for blue + 1 byte for green + 1 byte for red + 1 byte for attribute + 3 bytes : 1 byte for blue + 1 byte for green + 1 byte for red + 2 bytes : Bitmapped as a word in Intel byte + order as follows : + ARRRRRGG GGGBBBBB +????h ? byte Image data + For images of type 9 (using RLE), the image + data is divided into packets, the first byte + being the indicator for repetition or copy. + If bit 7 of the first byte is set, then repeat + (first byte and 07Fh+1) times the next byte, + otherwise copy first byte+1 pixels from data + stream. RLE packets may cross scan lines ! +EXTENSION:TGA +OCCURENCES:PC +SEE ALSO: +--------S-TXW------------------------------- +The TXW files are disk images used by the Yamaha TX-16W. +Further information wanted. +EXTENSION:TXW +--------S-UWF-G----------------------------- +The UWF files are sample files used by the UltraTracker. +Further information wanted. +OFFSET Count TYPE Description +0000h 32 char ASCIIZ sample name +0020h 1 char ID=1Ah +0021h 1 char ID=10h +0022h 5 char ID='MUWFB' +0027h 1 char ID=0 +0028h 6 char Length of sample as ASCII long integer +002Eh 1 word Length of sample +????? +EXTENSION:UWF +SEE ALSO:ULT +--------M-ULT------------------------------- +The ULT files are modules used by the UltraTracker. UltraTracker is a +module editor for the Gravis UltraSound soundcard. The version of the +file format used now is 6. + +OFFSET Count TYPE Description +0000h 11 char ID="MAS_UTrack_V" +000Ch 4 char Version number in 4-digit ASCII : + 1 - ULT version 1.0 + 2 - ULT version 2.0 + 3 - ULT version 2.1 + 4 - ULT version 2.2 +000Fh 32 char Song title +002Fh 1 byte Number of song text lines + ="NTL" +0030h "NTL"*32 char Song text +0030h+"NTL"*32 1 byte Number of samples + ="NOS" +0031h+"NTL"*32 "NOS" rec Sample structure + 32 byte Sample name + 12 byte DOS file name of sample + 1 dword Sample loop start + 1 dword Sample loop end + 1 dword Size start + 1 dword Size end + 1 byte Sample volume (linear) + 1 byte Bidirectional loop + 0 - No looping, forward playback, 8bit sample + 4 - No Looping, forward playback, 16bit sample + 8 - Loop Sample, forward playback, 8bit sample + 12 - Loop Sample, forward playback, 16bit sample + 24 - Loop Sample, reverse playback 8bit sample + 28 - Loop Sample, reverse playback, 16bit sample + 1 word Fine tune setting + 1 word C2-Frequency +0031h+"NTL"*32 + +"NOS"*64 256 byte Pattern orders +0131h+"NTL"*32 + +"NOS"*64 1 byte ="NOT" + Number of tracks -1 +0132h+"NTL"*32 + +"NOS"*64 1 byte ="NOT" + Number of patterns -1 +0133h+"NTL"*32 + +"NOS"*64 "NOT" byte Pan-position table (0-left, F-right) + +After the header there comes the event data. + +EXTENSION:ULT +SEE ALSO:UWF +--------S-WAVE------------------------------ +The Windows .WAV files are RIFF format files. Some programs expect the fmt block +right behind the RIFF header itself, so your programs should write out this +block as the first block in the RIFF file. + +The subblocks for the wave files are +RiffBLOCK [data] +This block contains the raw sample data. The necessary information +for playback is contained in the [fmt ] block. + +RiffBLOCK [fmt ] +This block contains the data necessary for playback of the sound +files. Note the blank after fmt ! +OFFSET Count TYPE Description +0000h 1 word Format tag + 1 = PCM (raw sample data) + 2 etc. for APCDM, a-Law, u-Law ... +0002h 1 word Channels (1=mono,2=stereo,...) +0004h 1 dword Sampling rate +0008h 1 dword Average bytes per second (=sampling rate*channels) +000Ch 1 word Block alignment / reserved ?? +000Eh 1 word Bits per sample (8/12/16-bit samples) + +RiffBLOCK [loop] +This block is for looped samples. Very few programs support this block, +but if your program changes the wave file, it should preserve any unknown +blocks. +OFFSET Count TYPE Description +0000h 1 dword Start of sample loop +0004h 1 dword End of sample loop + +EXTENSION:WAV +SEE ALSO:RIFF,VOC +OCCURENCES:PC +PROGRAMS:Windows,GUSWAV,WAV2VOC +VALIDATION:NONE +--------E-Windows PIF----------------------- +Windows also uses the PIF files for better performance under the DOS box. +The Windows extension of the original PIF format starts at offset 0171h. +OFFSET Count TYPE Description +********* not yet implemented ;-) +EXTENSION: +OCCURENCES: +PROGRAMS: +REFERENCE:DDJ #202 +SEE ALSO:PIF, WINDOWS NT PIF +VALIDATION: +--------W-WKS------------------------------- +The WKS files are worksheets/spreadsheets used by the Lotus 1-2-3 and Lotus +Symphony packages. More information has yet to be found since this information +origins from a magic file. +OFFSET Count TYPE Description +0000h 5 byte ID=0,0,2,0,4 +0005h 1 byte WKS type : + 4 - Lotus 1-2-3 v1.A WKS + 5 - Symphony 1.0 WKS + other - ?WK1 file? (Lotus 2.01+, Symphony 1.1+) +EXTENSION:WKS +OCCURENCES:PC +PROGRAMS:Lotus 1-2-3,Lotus Symphony +SEE ALSO:WKS +--------T-WORD-G---------------------------- +The Microsoft Word programs store their documents in files. The info comes +from a magic file and my own (not working) sources, so it is very unreliable +except for identification. +OFFSET Count TYPE Description +0000h 1 dword ID=31BE00 +0002h 1 byte Document type : + 0 - MS Word text + 1 - MS Text building block + 2 - Printer description file(maybe wrong topic) +0003h 1 byte ID=00 +0004h 1 word ID=AB00h + ToolID, different for the different versions ? +0006h 6 word reserved(0) +0008h 1 dword Textbytes??? Whatever +000Ch 1 word Paragraph information +000Eh 1 word Foot note table +0010h 1 word Section property +0012h 1 word Section table +0014h 1 word Page table +0016h 64 char Style sheet path +0056h 1 word Windows Write page count + Can be used to identify Windows Write files, + because it is 0 for MS Word and nonzero for + Windows Write documents. +0058h 8 char Printer name + Used under MS Word / WinWord only +0060h 1 word MS Word page count +0062h 8 byte Document properties +006Ah 1 byte Word version this file was made by +006Bh 1 bool Autosave flag +006Ch 1 word Word 5 page table +006Eh 1 word Mac bkmk (whatever) +0070h 1 word ?Offset of file name for autosave? +0072h 1 word Running head table +0074h 1 word Code page used making this document + +EXTENSION:DOC +OCCURENCES:PC +PROGRAMS:MS Word,Windows Write, WinWord +SEE ALSO: +VALIDATION: +--------T-WORDPERFERCT FILES---------------- +The WordPerfect files all have a common header - even tough I don't know +anything else about them. +OFFSET Count TYPE Description +0000h 4 char ID=255,"WPC" +0004h 4 byte unknown +0008h 1 byte ID=1 +0009h 1 byte Filetype (see table 0003) + +(Table 0003) +File types of WordPerfect files + 01h - macro file + 02h - WordPerfect help file + 03h - keyboard definition file + 0Ah - document file + 0Bh - dictionary file + 0Ch - thesaurus file + 0Dh - block + 0Eh - rectangular block + 0Fh - column block + 10h - printer resource file (PRS) + 11h - setup file + 12h - prefix information file + 13h - printer resource file (ALL) + 14h - display resource file (DRS) + 15h - overlay file (WP.FIL) + 16h - graphics file (WPG) + 17h - hyphenation code module + 18h - hyphenation data module + 19h - macro resource file (MRS) + 1Ah - graphics driver (WPD) + 1Bh - hyphenation lex module +EXTENSION:various +OCCURENCES:PC +--------W-WQ1------------------------------- +Similar to the WKS spreadsheet files, the Quattro Pro spreadsheet files exist, +and their header is somewhat similar. Info again from a magic file which +makes only identification possible. +OFFSET Count TYPE Description +0000h 1 dword ID=00000200h +0004h 1 char ID='Q' +EXTENSION:WQ1 +OCCURENCES:PC +PROGRAMS:Borland Quattro Pro +REFERENCE: +SEE ALSO:WKS +VALIDATION: +--------M-XM-------------------------------- +The .XM files (Extended Module) are multichannel MOD files created by Triton's +FastTracker ][. They feature up to 32 channels and different effects. FT 2 is +a shareware program. After the initial .XM header follows the pattern data, +after the patterns follow the instruments. + +OFFSET Count TYPE Description +0000h 17 char ID="Extended module: " +0011h 20 char Module name, padded with zeroes +0025h 1 char ID=01Ah +0026h 20 char Tracker name +003Ah 1 word Tracker revision number, hi-byte is major version +003Ch 1 dword Header size +0040h 1 word Song length in patterns +0042h 1 word Restart position +0044h 1 word Number of channels +0046h 1 word Number of patterns (< 256) + ="PAT" +0048h 1 word Number of instruments (<128) +004Ah 1 word Flags : + 0 - Linear frequency table / Amiga freq. table +004Ch 1 word Default tempo +004Eh 1 word Default BPM +0050h 256 byte Pattern order table + +--- Pattern header +The patterns are stored as ordinary MOD patterns, except that each note is +stored as 5 bytes: + + ? 1 (byte) Note (0-71, 0 = C-0) + +1 1 (byte) Instrument (0-128) + +2 1 (byte) Volume column byte (see below) + +3 1 (byte) Effect type + +4 1 (byte) Effect parameter + +A simle packing scheme is also adopted, so that the patterns do not become TOO +large: Since the MSB in the note value is never used, it is used for the +compression.If the bit is set, then the other bits are interpreted as follows: + + bit 0 set: Note byte ollows + 1 set: Instrument byte follows + 2 set: Volume column byte follows + 3 set: Effect byte follows + 4 set: Effect data byte follows + +OFFSET Count TYPE Description +0000h 1 dword Length of pattern block/header ?? +0004h 1 byte Pattern pack type +0005h 1 word Number of rows in pattern (1..256) +0007h 1 word Size of pattern data + ="PSZ" + "PSZ" byte Pattern data + +--- Instrument header +Each instrument has one or more sample headers following it. +OFFSET Count TYPE Description +0000h 1 dword Instrument block/header size +0004h 22 char ASCII Instrument name, 0 padded ? +001Ah 1 byte Instrument type (always 0) +001Bh 1 word Number of samples in instrument +001Dh 1 dword Sample header size +0021h 96 byte Sample numbers for all notes +0081h 48 byte Points of volume envelope +00C1h 48 byte Points of panning envelope +0101h 1 byte Number of volume points +0102h 1 byte Number of panning points +0103h 1 byte Volume sustain point +0104h 1 byte Volume loop start point +0105h 1 byte Volume loop end point +0106h 1 byte Panning sustain point +0107h 1 byte Panning loop start point +0108h 1 byte Panning loop end point +0109h 1 byte Volume type, bitmapped + 0 - Volume on + 1 - Sustain on + 2 - Loop on +010Ah 1 byte Panning type, bitmapped + 0 - Panning on + 1 - Sustain on + 2 - Loop on +010Bh 1 byte Vibrato type +010Ch 1 byte Vibrato sweep +010Dh 1 byte Vibrato depth +010Eh 1 byte Vibrato rate +010Fh 1 word Volume fadeout +0111h 1 word Reserved + +--- Sample headers +OFFSET Count TYPE Description +0000h 1 dword Sample length + ="LEN" +0004h 1 dword Sample loop start +0008h 1 dword Sample loop length +000Ch 1 byte Volume +000Dh 1 byte Finetune for sample (-128..+127) + +-127 is one half tone +000Eh 1 byte Sample type, bitmapped + 0,1 : Loop type : + 0 - no loop + 1 - forward loop + 2 - ping-pong loop + 3 - reserved + 4?: sample is 16-bit +000Fh 1 byte Sample pan +0010h 1 byte Relative note number (signed byte) + (-96..+95), 0 -> C-4 sounds as C-4 +0011h 1 byte Reserved +0012h 22 char ASCII name of sample, 0 padded +0013h "LEN" byte Sample data. The sample data is stored + as delta compressed data like the ProTracker. + +EXTENSION:XM,MOD +OCCURENCES: +PROGRAMS: +REFERENCE: +SEE ALSO:MOD,S3M +VALIDATION: +--------A-ZIP------------------------------- +The ZIP archives are created by the PkZIP/PkUnZIP combo produced +by the PkWare company. The PkZIP programs have with LHArc and ARJ +the best compression. +The directory information is stored at the end of the archive, each local +file in the archive begins with the following header; This header can be used +to identify a ZIP file as such : +OFFSET Count TYPE Description +0000h 4 char ID='PK',03,04 +0004h 1 word Version needed to extract archive +0006h 1 word General purpose bit field (bit mapped) + 0 - file is encrypted + 1 - 8K/4K sliding dictionary used + 2 - 3/2 Shannon-Fano trees were used + 3-4 - unused + 5-15 - used internally by ZIP + Note: Bits 1 and 2 are undefined if the + compression method is other than + type 6 (Imploding). +0008h 1 word Compression method (see table 0010) +000Ah 1 dword Original DOS file date/time (see table 0009) +000Eh 1 dword 32-bit CRC of file (inverse??) +0012h 1 dword Compressed file size +0016h 1 dword Uncompressed file size +001Ah 1 word Length of filename + ="LEN" +001Ch 1 word Length of extra field + ="XLN" +001Eh "LEN" char path/filename +001Eh "XLN" char extra field ++"LEN" +After all the files, there comes the central directory structure. +(Table 0010) +PkZip compression types +0 - Stored / No compression +1 - Shrunk / LZW, 8K buffer, 9-13 bits with partial clearing +2 - Reduced-1 / Probalistic compression, lower 7 bits +3 - Reduced-2 / Probalistic compression, lower 6 bits +4 - Reduced-3 / Probalistic compression, lower 5 bits +5 - Reduced-4 / Probalistic compression, lower 4 bits +6 - Imploded / 2/3 Shanno-Fano trees, 4K/8K sliding dictionary + +--- Central directory structure +The CDS is at the end of the archive and contains additional information +about the files stored within the archive. +OFFSET Count TYPE Description +0000h 4 char ID='PK',01,02 +0004h 1 byte Version made by +0005h 1 byte Host OS (see table 0011) +0006h 1 byte Minimum version needed to extract +0007h 1 byte Target OS + see above "Host OS" +0008h 1 word General purpose bit flag + see above "General purpose bit flag" +000Ah 1 word Compression method + see above "Compression method" +000Ch 1 dword DOS date / time of file +0010h 1 dword 32-bit CRC of file (see table 0009) +0014h 1 dword Compressed size of file +0018h 1 dword Uncompressed size of file +001Ch 1 word Length of filename + ="LEN" +001Eh 1 word Length of extra field + ="XLN" +0020h 1 word Length of file comment + ="CMT" +0022h 1 word Disk number ?? +0024h 1 word Internal file attributes (bit mapped) + 0 - file is apparently an ASCII/binary file + 1-15 - unused +0026h 1 dword External file attributes (OS dependent) +002Ah 1 dword Relative offset of local header from the + start of the first disk this file appears on +002Eh "LEN" char Filename / path; should not contain a drive + or device letter, all slashes should be forward + slashes '/'. +002Eh+ "XLN" char Extra field ++"LEN" +002Eh "CMT" char File comment ++"LEN" ++"XLN" + +(Table 0011) +PkZip Host OS table +0 - MS-DOS and OS/2 (FAT) +1 - Amiga +2 - VMS +3 - *nix +4 - VM/CMS +5 - Atari ST +6 - OS/2 1.2 extended file sys +7 - Macintosh +8-255 - unused + +--- End of central directory structure +The End of Central Directory Structure header has following format : +OFFSET Count TYPE Description +0000h 4 char ID='PK',05,06 +0004h 1 word Number of this disk +0006h 1 word Number of disk with start of central directory +0008h 1 word Total number of file/path entries on this disk +000Ah 1 word Total number of entries in central dir +000Ch 1 dword Size of central directory +0010h 1 dword Offset of start of central directory relative + to starting disk number +0014h 1 word Archive comment length + ="CML" +0016h "CML" char Zip file comment + +EXTENSION:ZIP +OCCURENCES:PC,Amiga,ST +PROGRAMS:PkZIP,WinZIP +REFERENCE:Technote.APP +--------A-ZOO------------------------------- +The ZOO archive program by Raoul Dhesi is a file compression program now +superceeded in both compression and speed by most other compression programs. +The archive header looks like this : +OFFSET Count TYPE Description +0000h 20 char Archive header text, ^Z terminated, null padded +0014h 1 dword ID=0FDC4A7DCh +0018h 1 dword Offset of first file in archive +001Ch 1 dword Offset of ???? +0020h 1 byte Version archive was made by +0021h 1 byte Minimum version needed to extract + +Each stored file has its own header, which looks like this : +OFFSET Count TYPE Description +0000h 1 dword ID=0FDC4A7DCh +0004h 1 byte Type of directory entry +0005h 1 byte Compression method : + 0 - stored + 1 - Crunched : LZW, 4K buffer, + var len (9-13 bits) +0006h 1 dword Offset of next directory entry +000Ah 1 dword Offset of next header +000Dh 1 word Original date / time of file (see table 0009) +0012h 1 word CRC-16 of file +0014h 1 dword Uncompressed size of file +0018h 1 dword Compressed size of file +001Ch 1 byte Version this file was compressed by +001Dh 1 byte Minimum version needed to extract +001Eh 1 byte Deleted flag + 0 - file in archive + 1 - file is considered deleted +001Fh 1 dword Offset of comment field, 0 if none +0023h 1 word Length of comment field +0025h ? char ASCIIZ path / filename + +EXTENSION:ZOO +OCCURENCES:PC +PROGRAMS:ZOO.EXE +REFERENCE: +VALIDATION: +--------S-ZyXEL----------------------------- +The ZyXEL Modems are capable of digitizing speech, the ZFAX software and +answering machine software like VoiceConnect store the sampled data in those +files. The Modems are capable of compressing the data down to 19.2k CPS (ADPCM) +and 9.6k CPS (CELP), the algorithms for the compression may be found in the +ZyxelVoc package by N. Igl, but as the firmware on the modems changes, so might +the compression algorithm. Playback on the modem is always possible. + +OFFSET Count TYPE Description +0000h 5 char ID='ZyXEL' +0005h 1 byte 02h, ??? format tag +0006h 4 byte reserved +000Ah 1 word Compression scheme + 0 - CELP + 1 - 2 bit ADPCM + 2 - 3 bit ADPCM +000Ch 4 byte reserved +0010h ? ???? Raw Data + The voice data is just + the data received from U1496 + Modem/Fax. +EXTENSION:ZVD,ZYX +OCCURENCES:PC +PROGRAMS:Voice Connect,ZFAX +REFERENCE:ZYXELVOC.* +VALIDATION:NONE +--------!-ALGORITHMS------------------------ +Some algorithms used for encoding images etc... +--- TIFF PackBits algorithm + + Abstract + + This document describes a simple compression scheme for bilevel + scanned and paint type files. + + + Motivation + + The TIFF specification defines a number of compression schemes. + Compression type 1 is really no compression, other than basic + pixel packing. Compression type 2, based on CCITT 1D + compression, is powerful, but not trivial to implement. + Compression type 5 is typically very effective for most bilevel + images, as well as many deeper images such as palette color and + grayscale images, but is also not trivial to implement. PackBits + is a simple but often effective alternative. + + + Description + + Several good schemes were already in use in various settings. We + somewhat arbitrarily picked the Macintosh PackBits scheme. It is + byte oriented, so there is no problem with word alignment. And + it has a good worst case behavior (at most 1 extra byte for every + 128 input bytes). For Macintosh users, there are toolbox + utilities PackBits and UnPackBits that will do the work for you, + but it is easy to implement your own routines. + + A pseudo code fragment to unpack might look like this: + + Loop until you get the number of unpacked bytes you are + expecting: + Read the next source byte into n. + If n is between 0 and 127 inclusive, copy the next n+1 bytes + literally. + Else if n is between -127 and -1 inclusive, copy the next + byte -n+1 times. + Else if n is 128, noop. + Endloop + + In the inverse routine, it's best to encode a 2-byte repeat run + as a replicate run except when preceded and followed by a literal + run, in which case it's best to merge the three into one literal + run. Always encode 3-byte repeats as replicate runs. + + So that's the algorithm. Here are some other rules: + + o Each row must be packed separately. Do not compress across + row boundaries. + + o The number of uncompressed bytes per row is defined to be + (ImageWidth + 7) / 8. If the uncompressed bitmap is required to + have an even number of bytes per row, decompress into word- + aligned buffers. + o If a run is larger than 128 bytes, simply encode the + remainder of the run as one or more additional replicate runs. + + When PackBits data is uncompressed, the result should be + interpreted as per compression type 1 (no compression). + +--- TIFF LZW Compression + + Abstract + + This document describes an adaptive compression scheme for raster + images. + + Reference + + Terry A. Welch, "A Technique for High Performance Data + Compression", IEEE Computer, vol. 17 no. 6 (June 1984). + Describes the basic Lempel-Ziv & Welch (LZW) algorithm. The + author's goal in the article is to describe a hardware-based + compressor that could be built into a disk controller or database + engine, and used on all types of data. There is no specific + discussion of raster images. We intend to give sufficient + information in this Appendix so that the article is not required + reading. + + Requirements + + A compression scheme with the following characteristics should + work well in a desktop publishing environment: + + o Must work well for images of any bit depth, including images + deeper than 8 bits per sample. + o Must be effective: an average compression ratio of at least + 2:1 or better. And it must have a reasonable worst-case + behavior, in case something really strange is thrown at it. + o Should not depend on small variations between pixels. + Palette color images tend to contain abrupt changes in index + values, due to common patterning and dithering techniques. These + abrupt changes do tend to be repetitive, however, and the scheme + should make use of this fact. + o For images generated by paint programs, the scheme should + not depend on a particular pattern width. 8x8 pixel patterns are + common now, but we should not assume that this situation will not + change. + o Must be fast. It should not take more than 5 seconds to + decompress a 100K byte grayscale image on a 68020- or 386-based + computer. Compression can be slower, but probably not by more + than a factor of 2 or 3. + o The level of implementation complexity must be reasonable. + We would like something that can be implemented in no more than a + couple of weeks by a competent software engineer with some + experience in image processing. The compiled code for + compression and decompression combined should be no more than + about 10K. + o Does not require floating point software or hardware. + + + The following sections describe an algorithm based on the "LZW" + (Lempel-Ziv & Welch) technique that meets the above requirements. + In addition meeting our requirements, LZW has the following + characteristics: + + o LZW is fully reversible. All information is preserved. But + if noise or information is removed from an image, perhaps by + smoothing or zeroing some low-order bitplanes, LZW compresses + images to a smaller size. Thus, 5-bit, 6-bit, or 7-bit data + masquerading as 8-bit data compresses better than true 8-bit + data. Smooth images also compress better than noisy images, and + simple images compress better than complex images. + o On a 68082- or 386-based computer, LZW software can be + written to compress at between 30K and 80K bytes per second, + depending on image characteristics. LZW decompression speeds are + typically about 50K bytes per second. + o LZW works well on bilevel images, too. It always beats + PackBits, and generally ties CCITT 1D (Modified Huffman) + compression, on our test images. Tying CCITT 1D is impressive in + that LZW seems to be considerably faster than CCITT 1D, at least + in our implementation. + o Our implementation is written in C, and compiles to about 2K + bytes of object code each for the compressor and decompressor. + o One of the nice things about LZW is that it is used quite + widely in other applications such as archival programs, and is + therefore more of a known quantity. + + + The Algorithm + + Each strip is compressed independently. We strongly recommend + that RowsPerStrip be chosen such that each strip contains about + 8K bytes before compression. We want to keep the strips small + enough so that the compressed and uncompressed versions of the + strip can be kept entirely in memory even on small machines, but + large enough to maintain nearly optimal compression ratios. + + The LZW algorithm is based on a translation table, or string + table, that maps strings of input characters into codes. The + TIFF implementation uses variable-length codes, with a maximum + code length of 12 bits. This string table is different for every + strip, and, remarkably, does not need to be kept around for the + decompressor. The trick is to make the decompressor + automatically build the same table as is built when compressing + the data. We use a C-like pseudocode to describe the coding + scheme: + + InitializeStringTable(); + WriteCode(ClearCode); + Omega = the empty string; + for each character in the strip { + K = GetNextCharacter(); + if Omega+K is in the string table { + Omega = Omega+K; /* string concatenation */ + } else { + WriteCode (CodeFromString(Omega)); + AddTableEntry(Omega+K); + Omega = K; + } + } /* end of for loop */ + WriteCode (CodeFromString(Omega)); + WriteCode (EndOfInformation); + + That's it. The scheme is simple, although it is fairly + challenging to implement efficiently. But we need a few + explanations before we go on to decompression. + + The "characters" that make up the LZW strings are bytes + containing TIFF uncompressed (Compression=1) image data, in our + implementation. For example, if BitsPerSample is 4, each 8-bit + LZW character will contain two 4-bit pixels. If BitsPerSample is + 16, each 16-bit pixel will span two 8-bit LZW characters. + + (It is also possible to implement a version of LZW where the LZW + character depth equals BitsPerSample, as was described by Draft 2 + of Revision 5.0. But there is a major problem with this + approach. If BitsPerSample is greater than 11, we can not use + 12-bit-maximum codes, so that the resulting LZW table is + unacceptably large. Fortunately, due to the adaptive nature of + LZW, we do not pay a significant compression ratio penalty for + combining several pixels into one byte before compressing. For + example, our 4-bit sample images compressed about 3 percent + worse, and our 1-bit images compressed about 5 percent better. + And it is easier to write an LZW compressor that always uses the + same character depth than it is to write one which can handle + varying depths.) + + We can now describe some of the routine and variable references + in our pseudocode: + + InitializeStringTable() initializes the string table to contain + all possible single-character strings. There are 256 of them, + numbered 0 through 255, since our characters are bytes. + + WriteCode() writes a code to the output stream. The first code + written is a Clear code, which is defined to be code #256. + + Omega is our "prefix string." + + GetNextCharacter() retrieves the next character value from the + input stream. This will be number between 0 and 255, since our + characters are bytes. + + The "+" signs indicate string concatenation. + + AddTableEntry() adds a table entry. (InitializeStringTable() has + already put 256 entries in our table. Each entry consists of a + single-character string, and its associated code value, which is, + in our application, identical to the character itself. That is, + the 0th entry in our table consists of the string <0>, with + corresponding code value of <0>, the 1st entry in the table + consists of the string <1>, with corresponding code value of <1>, + ..., and the 255th entry in our table consists of the string + <255>, with corresponding code value of <255>.) So the first + entry that we add to our string table will be at position 256, + right? Well, not quite, since we will reserve code #256 for a + special "Clear" code, and code #257 for a special + "EndOfInformation" code that we will write out at the end of the + strip. So the first multiple-character entry added to the string + table will be at position 258. + + Let's try an example. Suppose we have input data that looks + like: + + Pixel 0: <7> + Pixel 1: <7> + Pixel 2: <7> + Pixel 3: <8> + Pixel 4: <8> + Pixel 5: <7> + Pixel 6: <7> + Pixel 7: <6> + Pixel 8: <6> + + First, we read Pixel 0 into K. OmegaK is then simply <7>, since Omega is + the empty string at this point. Is the string <7> already in the + string table? Of course, since all single character strings were + put in the table by InitializeStringTable(). So set Omega equal to + <7>, and go to the top of the loop. + + Read Pixel 1 into K. Does OmegaK (<7><7>) exist in the string table? + No, so we get to do some real work. We write the code associated + with Omega to output (write <7> to output), and add OmegaK (<7><7>) to + the table as entry 258. Store K (<7>) into Omega. Note that + although we have added the string consisting of Pixel 0 and Pixel + 1 to the table, we "re-use" Pixel 1 as the beginning of the next + string. + + Back at the top of the loop. We read Pixel 2 into K. Does OmegaK + (<7><7>) exist in the string table? Yes, the entry we just + added, entry 258, contains exactly <7><7>. So we just add K onto + the end of Omega, so that Omega is now <7><7>. + + Back at the top of the loop. We read Pixel 3 into K. Does OmegaK + (<7><7><8>) exist in the string table? No, so write the code + associated with Omega (<258>) to output, and add OmegaK to the table as + entry 259. Store K (<8>) into Omega. + + Back at the top of the loop. We read Pixel 4 into K. Does OmegaK + (<8><8>) exist in the string table? No, so write the code + associated with Omega (<8>) to output, and add OmegaK to the table as + entry 260. Store K (<8>) into Omega. + + Continuing, we get the following results: + + After reading: We write to output: And add table entry: + Pixel 0 + Pixel 1 <7> 258: <7><7> + Pixel 2 + Pixel 3 <258> 259: <7><7><8> + Pixel 4 <8> 260: <8><8> + Pixel 5 <8> 261: <8><7> + Pixel 6 + Pixel 7 <258> 262: <7><7><6> + Pixel 8 <6> 263: <6><6> + + WriteCode() also requires some explanation. The output code + stream, <7><258><8><8><258><6>... in our example, should be + written using as few bits as possible. When we are just starting + out, we can use 9-bit codes, since our new string table entries + are greater than 255 but less than 512. But when we add table + entry 512, we must switch to 10-bit codes. Likewise, we switch + to 11-bit codes at 1024, and 12-bit codes at 2048. We will + somewhat arbitrarily limit ourselves to 12-bit codes, so that our + table can have at most 4096 entries. If we push it any farther, + tables tend to get too large. + + What happens if we run out of room in our string table? This is + where the afore-mentioned Clear code comes in. As soon as we use + entry 4094, we write out a (12-bit) Clear code. (If we wait any + dworder to write the Clear code, the decompressor might try to + interpret the Clear code as a 13-bit code.) At this point, the + compressor re-initializes the string table and starts writing out + 9-bit codes again. + + Note that whenever you write a code and add a table entry, Omega is + not left empty. It contains exactly one character. Be careful + not to lose it when you write an end-of-table Clear code. You + can either write it out as a 12-bit code before writing the Clear + code, in which case you will want to do it right after adding + table entry 4093, or after the clear code as a 9-bit code. + Decompression gives the same result in either case. + + To make things a little simpler for the decompressor, we will + require that each strip begins with a Clear code, and ends with + an EndOfInformation code. + + Every LZW-compressed strip must begin on a byte boundary. It + need not begin on a word boundary. LZW compression codes are + stored into bytes in high-to-low-order fashion, i.e., FillOrder + is assumed to be 1. The compressed codes are written as bytes, + not words, so that the compressed data will be identical + regardless of whether it is an "II" or "MM" file. + + Note that the LZW string table is a continuously updated history + of the strings that have been encountered in the data. It thus + reflects the characteristics of the data, providing a high degree + of adaptability. + + + LZW Decoding + + The procedure for decompression is a little more complicated, but + still not too bad: + + while ((Code = GetNextCode()) != EoiCode) { + if (Code == ClearCode) { + InitializeTable(); + Code = GetNextCode(); + if (Code == EoiCode) + break; + WriteString(StringFromCode(Code)); + OldCode = Code; + } /* end of ClearCode case */ + + else { + if (IsInTable(Code)) { + WriteString(StringFromCode(Code)); + AddStringToTable(StringFromCode(OldCode)+ + FirstChar(StringFromCode(Code))); + OldCode = Code; + } else { + OutString = StringFromCode(OldCode) + + FirstChar(StringFromCode(OldCode)); + WriteString(OutString); + AddStringToTable(OutString); + OldCode = Code; + } + } /* end of not-ClearCode case */ + } /* end of while loop */ + + The function GetNextCode() retrieves the next code from the LZW- + coded data. It must keep track of bit boundaries. It knows that + the first code that it gets will be a 9-bit code. We add a table + entry each time we get a code, so GetNextCode() must switch over + to 10-bit codes as soon as string #511 is stored into the table. + + The function StringFromCode() gets the string associated with a + particular code from the string table. + + The function AddStringToTable() adds a string to the string + table. The "+" sign joining the two parts of the argument to + AddStringToTable indicate string concatenation. + + StringFromCode() looks up the string associated with a given + code. + + WriteString() adds a string to the output stream. + + + When SamplesPerPixel Is Greater Than 1 + + We have so far described the compression scheme as if + SamplesPerPixel were always 1, as will be be the case with + palette color and grayscale images. But what do we do with RGB + image data? + + Tests on our sample images indicate that the LZW compression + ratio is nearly identical regardless of whether + PlanarConfiguration=1 or PlanarConfiguration=2, for RGB images. + So use whichever configuration you prefer, and simply compress + the bytes in the strip. + + It is worth cautioning that compression ratios on our test RGB + images were disappointing low: somewhere between 1.1 to 1 and 1.5 + to 1, depending on the image. Vendors are urged to do what they + can to remove as much noise from their images as possible. + Preliminary tests indicate that significantly better compression + ratios are possible with less noisy images. Even something as + simple as zeroing out one or two least-significant bitplanes may + be quite effective, with little or no perceptible image + degradation. + + + Implementation + + The exact structure of the string table and the method used to + determine if a string is already in the table are probably the + most significant design decisions in the implementation of a LZW + compressor and decompressor. Hashing has been suggested as a + useful technique for the compressor. We have chosen a tree based + approach, with good results. The decompressor is actually more + straightforward, as well as faster, since no search is + involved - strings can be accessed directly by code value. + + + Performance + + Many people do not realize that the performance of any + compression scheme depends greatly on the type of data to which + it is applied. A scheme that works well on one data set may do + poorly on the next. + + But since we do not want to burden the world with too many + compression schemes, an adaptive scheme such as LZW that performs + quite well on a wide range of images is very desirable. LZW may + not always give optimal compression ratios, but its adaptive + nature and relative simplicity seem to make it a good choice. + + Experiments thus far indicate that we can expect compression + ratios of between 1.5 and 3.0 to 1 from LZW, with no loss of + data, on continuous tone grayscale scanned images. If we zero + the least significant one or two bitplanes of 8-bit data, higher + ratios can be achieved. These bitplanes often consist chiefly of + noise, in which case little or no loss in image quality will be + perceived. Palette color images created in a paint program + generally compress much better than continuous tone scanned + images, since paint images tend to be more repetitive. It is not + unusual to achieve compression ratios of 10 to 1 or better when + using LZW on palette color paint images. + + By way of comparison, PackBits, used in TIFF for black and white + bilevel images, does not do well on color paint images, much less + continuous tone grayscale and color images. 1.2 to 1 seemed to + be about average for 4-bit images, and 8-bit images are worse. + + It has been suggested that the CCITT 1D scheme could be used for + continuous tone images, by compressing each bitplane separately. + No doubt some compression could be achieved, but it seems + unlikely that a scheme based on a fixed table that is optimized + for word black runs separated by dworder white runs would be a + very good choice on any of the bitplanes. It would do quite well + on the high-order bitplanes (but so would a simpler scheme like + PackBits), and would do quite poorly on the low-order bitplanes. + We believe that the compression ratios would generally not be + very impressive, and the process would in addition be quite slow. + Splitting the pixels into bitplanes and putting them back + together is somewhat expensive, and the coding is also fairly + slow when implemented in software. + + Another approach that has been suggested uses uses a 2D + differencing step following by coding the differences using a + fixed table of variable-length codes. This type of scheme works + quite well on many 8-bit grayscale images, and is probably + simpler to implement than LZW. But it has a number of + disadvantages when used on a wide variety of images. First, it + is not adaptive. This makes a big difference when compressing + data such as 8-bit images that have been "sharpened" using one of + the standard techniques. Such images tend to get larger instead + of smaller when compressed. Another disadvantage of these + schemes is that they do not do well with a wide range of bit + depths. The built-in code table has to be optimized for a + particular bit depth in order to be effective. + + Finally, we should mention "lossy" compression schemes. + Extensive research has been done in the area of lossy, or non- + information-preserving image compression. These techniques + generally yield much higher compression ratios than can be + achieved by fully-reversible, information-preserving image + compression techniques such as PackBits and LZW. Some + disadvantages: many of the lossy techniques are so + computationally expensive that hardware assists are required. + Others are so complicated that most microcomputer software + vendors could not afford either the expense of implementation or + the increase in application object code size. Yet others + sacrifice enough image quality to make them unsuitable for + publishing use. + + In spite of these difficulties, we believe that there will one + day be a standardized lossy compression scheme for full color + images that will be usable for publishing applications on + microcomputers. An International Standards Organization group, + ISO/IEC/JTC1/SC2/WG8, in cooperation with CCITT Study Group VIII, + is hard at work on a scheme that might be appropriate. We expect + that a future revision of TIFF will incorporate this scheme once + it is finalized, if it turns out to satisfy the needs of desktop + publishers and others in the microcomputer community. This will + augment, not replace, LZW as an approved TIFF compression scheme. + LZW will very likely remain the scheme of choice for Palette + color images, and perhaps 4-bit grayscale images, and may well + overtake CCITT 1D and PackBits for bilevel images. + + + Future LZW Extensions + + Some images compress better using LZW coding if they are first + subjected to a process wherein each pixel value is replaced by + the difference between the pixel and the preceding pixel. + Performing this differencing in two dimensions helps some images + even more. However, many images do not compress better with this + extra preprocessing, and for a significant number of images, the + compression ratio is actually worse. We are therefore not making + differencing an integral part of the TIFF LZW compression scheme. + + However, it is possible that a "prediction" stage like + differencing may exist which is effective over a broad range of + images. If such a scheme is found, it may be incorporated in the + next major TIFF revision. If so, a new value will be defined for + the new "Predictor" TIFF tag. Therefore, all TIFF readers that + read LZW files must pay attention to the Predictor tag. If it is + 1, which is the default case, LZW decompression may proceed + safely. If it is not 1, and the reader does not recognize the + specified prediction scheme, the reader should give up. + + + Acknowledgements + + The original LZW reference has already been given. The use of + ClearCode as a technique to handle overflow was borrowed from the + compression scheme used by the Graphics Interchange Format (GIF), + a small-color-paint-image-file format used by CompuServe that + also is an adaptation of the LZW technique. Joff Morgan and Eric + Robinson of Aldus were each instrumental in their own way in + getting LZW off the ground. + + The TIFF predictor algorithm + + The idea is to make use of the fact that many continuous tone + images rarely vary much in pixel value from one pixel to the + next. In such images, if we replace the pixel values by + differences between consecutive pixels, many of the differences + should be 0, plus or minus 1, and so on. This reduces the + apparent information content, and thus allows LZW to encode the + data more compactly. + + Assuming 8-bit grayscale pixels for the moment, a basic C + implementation might look something like this: + + char image[ ][ ]; + int row, col; + + /* take horizontal differences: + */ + for (row = 0; row < nrows; row++) + for (col = ncols - 1; col >= 1; col--) + image[row][col] -= image[row][col-1]; + + If we don't have 8-bit samples, we need to work a little harder, + so that we can make better use of the architecture of most CPUs. + Suppose we have 4-bit samples, packed two to a byte, in normal + TIFF uncompressed (i.e., Compression=1) fashion. In order to + find differences, we want to first expand each 4-bit sample into + an 8-bit byte, so that we have one sample per byte, low-order + justified. We then perform the above horizontal differencing. + Once the differencing has been completed, we then repack the 4- + bit differences two to a byte, in normal TIFF uncompressed + fashion. + + If the samples are greater than 8 bits deep, expanding the + samples into 16-bit words instead of 8-bit bytes seems like the + best way to perform the subtraction on most computers. + + Note that we have not lost any data up to this point, nor will we + lose any data later on. It might at first seem that our + differencing might turn 8-bit samples into 9-bit differences, 4- + bit samples into 5-bit differences, and so on. But it turns out + that we can completely ignore the "overflow" bits caused by + subtracting a larger number from a smaller number and still + reverse the process without error. Normal twos complement + arithmetic does just what we want. Try an example by hand if you + need more convincing. + + Up to this point we have implicitly assumed that we are + compressing bilevel or grayscale images. An additional + consideration arises in the case of color images. + + If PlanarConfiguration is 2, there is no problem. Differencing + proceeds the same way as it would for grayscale data. + + If PlanarConfiguration is 1, however, things get a little + trickier. If we didnt do anything special, we would be + subtracting red sample values from green sample values, green + sample values from blue sample values, and blue sample values + from red sample values, which would not give the LZW coding stage + much redundancy to work with. So we will do our horizontal + differences with an offset of SamplesPerPixel (3, in the RGB + case). In other words, we will subtract red from red, green from + green, and blue from blue. The LZW coding stage is identical to + the SamplesPerPixel=1 case. We require that BitsPerSample be the + same for all 3 samples. + + + Results and guidelines + + LZW without differencing works well for 1-bit images, 4-bit + grayscale images, and synthetic color images. But natural 24-bit + color images and some 8-bit grayscale images do much better with + differencing. For example, our 24-bit natural test images hardly + compressed at all using "plain" LZW: the average compression + ratio was 1.04 to 1. The average compression ratio with + horizontal differencing was 1.40 to 1. (A compression ratio of + 1.40 to 1 means that if the uncompressed image is 1.40MB in size, + the compressed version is 1MB in size.) + + Although the combination of LZW coding with horizontal + differencing does not result in any loss of data, it may be + worthwhile in some situations to give up some information by + removing as much noise as possible from the image data before + doing the differencing, especially with 8-bit samples. The + simplest way to get rid of noise is to mask off one or two low- + order bits of each 8-bit sample. On our 24-bit test images, LZW + with horizontal differencing yielded an average compression ratio + of 1.4 to 1. When the low-order bit was masked from each sample, + the compression ratio climbed to 1.8 to 1; the compression ratio + was 2.4 to 1 when masking two bits, and 3.4 to 1 when masking + three bits. Of course, the more you mask, the more you risk + losing useful information adword with the noise. We encourage you + to experiment to find the best compromise for your device. For + some applications it may be useful to let the user make the final + decision. + + Interestingly, most of our RGB images compressed slightly better + using PlanarConfiguration=1. One might think that compressing + the red, green, and blue difference planes separately + (PlanarConfiguration=2) might give better compression results + than mixing the differences together before compressing + (PlanarConfiguration=1), but this does not appear to be the case. + + Incidentally, we tried taking both horizontal and vertical + differences, but the extra complexity of two-dimensional + differencing did not appear to pay off for most of our test + images. About one third of the images compressed slightly better + with two-dimensional differencing, about one third compressed + slightly worse, and the rest were about the same. + +--- BMP RLE_8 compression + + The BMP can be compressed in two modes, absolute mode and RLE + mode. Both modes can occur anywhere in a single bitmap. + + The RLE mode is a simple RLE mechanism, the first byte contains the + count, the second byte the pixel to be replicatet. If the count byte + is 0, the second byte is a special, like EOL or delta. + + In absolute mode, the second byte contains the number of bytes to be + copied litteraly. Each absolute run must be word-aligned that means you + will may have to add an aditional padding byte which is not included + in the count. After an absolute run, RLE compression continues. + + Second byte Meaning + + 0 End of line + 1 End of bitmap + 2 Delta. The next two bytes are the horizontal + and vertical offsets from the current position + to the next pixel. + 3-255 Switch to absolute mode + +--- BMP RLE_4 compression + + RLE_4 compression knows the two modes of the RLE_8 compression, + absolute and RLE. In the RLE mode, the first byte contains the count + of pixels to draw, the second byte contains in its two nibbles the + indices off the pixel colors, the higher 4 bits are the left pixel, + the lower 4 bits are the right pixel. Note that two-color runs are + possible to encode with RLE_4 through this. + +--- Protracker sample compression / decompression + + Get the number of sample bytes to process. + Call this SamplesLeft. + + Set Delta counter to 0. + + DO + Get a byte from the buffer. + Store the byte in Temp. + Subtract the Delta counter from the byte. + Store it in the buffer. + Move the Temp byte into the Delta Counter + Decrement SamplesLeft. + WHILE(SamplesLeft <> 0) + + The technique for conversion back to the raw data is: + + Get the number of sample bytes to process. + Call this SamplesLeft. + + Set Delta counter to 0. + + DO + Get a byte from the buffer. + Add onto the byte the Delta Counter. + Store the byte in Delta Counter. + Store the byte in Temp. + Decrement SamplesLeft. + WHILE(SamplesLeft <> 0) +--------!-ADDRESSES------------------------- +Useful adresses + +International Midi Association +5316 West 57th Street +Los Angeles, CA 90056 +xx1-213-649-6434 +xx1-213-215-3380 fax +--------!-HISTORY--------------------------- +History is kept within this file for convenience whilst editing ... +Date format is european/german, just for my convenience. + +Date Who What +14.03.95 MM Introduced tables + Last table number=0012 +05.06.95 MM + PTM format +25.07.95 MM + PIF format + + Paradox format description +11.08.95 MM + MS Compress variants +18.11.95 MM + ARC enhancements, caveats + + HA files +22.11.95 MM + Parts of the .CRD files +01.02.96 MM + PNG structure +02.02.96 MM + More on JPEG + + TARGA entry created \ No newline at end of file diff --git a/docs/future/FILEFMTS_ARC.md b/docs/future/FILEFMTS_ARC.md new file mode 100644 index 000000000..4cbb187f5 --- /dev/null +++ b/docs/future/FILEFMTS_ARC.md @@ -0,0 +1,98 @@ +ARC +=== + +The ARC files are archive files created by the SEA ARC program. The compression +has been superceded by more recent compression programs. Similar archives can +be created by the PAK and PkPAK programs. There have been many variations +and enhancements to the ARC format though not as many as to the TIFF format. + +You may have to use some (paranoid) checks to ensure that you actually are +processing an ARC file, since other archivers also adopted the idea of putting +a 01Ah byte at offset 0, namely the Hyper archiver. To check if you have a +Hyper-archive, check the next two bytes for "HP" or "ST" (or look below for +"HYP"). Also the ZOO archiver also does put a 01Ah at the start of the file, +see the ZOO entry below. +``` +OFFSET Count TYPE Description +0000h 1 byte ID=1Ah +0001h 1 byte Compression method (see table 0001) +0002h 12 char File name +000Fh 1 dword Compressed file size +0013h 1 dword File date in MS-DOS format (see table 0009) +0017h 1 word 16-bit CRC +0019h 1 dword Original file size + ="SIZ" +``` + +| (Table 0001) | ARC compression types | +|-----------:|:----------------------| +| 0 | End of archive marker +| 1 | unpacked (obsolete) | ARC 1.0 ? +| 2 | unpacked | ARC 3.1 +| 3 | packed (RLE encoding) +| 4 | squeezed (after packing) +| 5 | crunched (obsolete) | ARC 4.0 +| 6 | crunched (after packing) (obsolete) | ARC 4.1 +| 7 | crunched (after packing, using faster hash algorithm) | ARC 4.6 +| 8 | crunched (after packing, using dynamic LZW variations) | ARC 5.0 +| 9 | Squashed c/o Phil Katz (no packing) (var. on crunching) +| 10 | crushed (PAK only) +| 11 | distilled (PAK only) +|12-19 | to 19 unknown (ARC 6.0 or later) | ARC 7.0 (?) +|20-29 | ?informational items? | ARC 6.0 +|30-39 | ?control items? | ARC 6.0 +| 40+ | reserved + +According to SEA's technical memo, the information and control items +were added to ARC 6.0. Information items use the same headers as archived +files, although the original file size (and name?) can be ignored. + +OFFSET Count TYPE Description +0000h 2 byte Length of header (includes "length" + and "type"?) +0002h 1 byte (sub)type +0003h ? byte data + +Informational item types as used by ARC 6.0 : + +Block type Subtype Description + 20 archive info + 0 archive description (ASCIIZ) + 1 name of creator program (ASCIIZ) + 2 name of modifier program (ASCIIZ) + + 21 file info + 0 file description (ASCIIZ) + 1 long name (if not MS-DOS "8.3" filename) + 2 extended date-time info (reserved) + 3 icon (reserved) + 4 file attributes (ASCIIZ) + + Attributes use an uppercase letter to signify the + following: + + R read access + W write access + H hidden file + S system file + N network shareable + + 22 operating system info (reserved) + +(Table 0009) +Format of the MS-DOS time stamp (32-bit) +The MS-DOS time stamp is limited to an even count of seconds, since the +count for seconds is only 5 bits wide. +``` + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 + |<---- year-1980 --->|<- month ->|<--- day ---->| + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + |<--- hour --->|<---- minute --->|<- second/2 ->| + +EXTENSION:ARC,PAK +OCCURENCES:PC +PROGRAMS:SEA ARC,PAK,PkPAK +SEE ALSO:HYP,ZOO +VALIDATION:FileSize="SIZ" +``` diff --git a/docs/future/FILEFMTS_ARJ.md b/docs/future/FILEFMTS_ARJ.md new file mode 100644 index 000000000..10a085e79 --- /dev/null +++ b/docs/future/FILEFMTS_ARJ.md @@ -0,0 +1,71 @@ +--------A-ARJ------------------------------- +The ARJ program by Robert K. Jung is a "newcomer" which compares well to PKZip +and LhArc in both compression and speed. An ARJ archive contains two types of +header blocks, one archive main header at the head of the archive and local +file headers before each archived file. + +OFFSET Count TYPE Description +0000h 1 word ID=0EA60h +0002h 1 word Basic header size (0 if end of archive) +0004h 1 byte Size of header including extra data +0005h 1 byte Archiver version number +0006h 1 byte Minimum version needed to extract +0007h 1 byte Host OS (see table 0002) +0008h 1 byte Internal flags, bitmapped : + 0 - no password / password + 1 - reserved + 2 - file continues on next disk + 3 - file start position field is available + 4 - path translation ( "\" to "/" ) +0009h 1 byte Compression method : + 0 - stored + 1 - compressed most + 2 - compressed + 3 - compressed faster + 4 - compressed fastest + Methods 1 to 3 use Lempel-Ziv 77 sliding window + with static Huffman encoding, method 4 uses + Lempel-Ziv 77 sliding window with pointer/ + length unary encoding. +000Ah 1 byte File type : + 0 - binary + 1 - 7-bit text + 2 - comment header + 3 - directory + 4 - volume label +000Bh 1 byte reserved +000Ch 1 dword Date/Time of original file in MS-DOS format +0010h 1 dword Compressed size of file +0014h 1 dword Original size of file +0018h 1 dword Original file's CRC-32 +001Ah 1 word Filespec position in filename +001Ch 1 word File attributes +001Eh 1 word Host data (currently not used) +? 1 dword Extended file starting position when used + (see above) + ? char ASCIIZ file name + ? char Comment +????h 1 dword Basic header CRC-32 +????h 1 word Size of first extended header (0 if none) + ="SIZ" +????h+"SIZ"+2 1 dword Extended header CRC-32 +????h+"SIZ"+6 ? byte Compressed file + +(Table 0002) +ARJ HOST-OS types + 0 - MS-DOS + 1 - PRIMOS + 2 - UNIX + 3 - AMIGA + 4 - MAC-OS (System xx) + 5 - OS/2 + 6 - APPLE GS + 7 - ATARI ST + 8 - NeXT + 9 - VAX VMS +EXTENSION:ARJ +OCCURENCES:PC +PROGRAMS:ARJ.EXE +REFERENCE: +SEE ALSO: +VALIDATION: diff --git a/docs/future/FILEFMTS_DWC.md b/docs/future/FILEFMTS_DWC.md new file mode 100644 index 000000000..572b3832f --- /dev/null +++ b/docs/future/FILEFMTS_DWC.md @@ -0,0 +1,36 @@ +DWC +=== + +The DWC archives seem to be a relict from ancient computing times - I've never +seen any program that dealt with them or could create them. They are yet +included in this compilation for reasons I don't know. But maybe one of you +stumbles over such a file, he might find this documentation helpful. +The DWC archives consist of single file entries with one archive trailer. The +archive entries seem to be at the start of the archive, but maybe they are +stored at the end of the archive, before the trailer. Each file header has the +following format : + +``` +OFFSET Count TYPE Description +0000h 13 char Name of the original file in ASCIIZ. +000Dh 1 dword Size of the original file +0011h 1 dword MS-DOS date and time of the original file +0015h 1 dword Size of the compressed file +0019h 1 dword Offset of compressed data in archive file +001Dh 3 byte reserved +0020h 1 byte Method : + 1 - crunched + 2 - stored + +The trailer at the end of each archive has the following format : +OFFSET Count TYPE Description +0000h 1 word Length of trailer (=27) +0002h 1 word Size of the directory entries (=34)?? +0004h 16 byte reserved +0014h 1 dword Count of the directory entries +0018h 3 char ID="DWC" + +EXTENSION:DWC?? +OCCURENCES:PC?? +PROGRAMS:DWC.EXE?? +``` diff --git a/docs/future/FILEFMTS_GZIP.md b/docs/future/FILEFMTS_GZIP.md new file mode 100644 index 000000000..49f7b6775 --- /dev/null +++ b/docs/future/FILEFMTS_GZIP.md @@ -0,0 +1,30 @@ +--------A-GZIP------------------------------ +The GNU ZIP program is an archive program mostly for the UNIX machines developed +by the GNU project. +OFFSET Count TYPE Description +0000h 2 char ID='!',139 +0002h 1 byte Method : + 0-7 - reserved + 8 - deflated +0003h 1 byte File flags : + 0 - ASCII-text + 1 - Multi-part file + 2 - Name present + 3 - Comment present + 4 - Encrypted + 5-8 - reserved +0004h 1 dword File date and time (see table 0009) +0008h 1 byte Extra flags +0009h 1 byte Target OS : + 0 - DOS + 1 - Amiga + 2 - VMS + 3 - Unix + 4 - ???? + 5 - Atari + 6 - OS/2 + 7 - MacOS + 10 - TOPS-20 + 11 - Win/32 +EXTENSION:ZIP +PROGRAMS:GNU gzip diff --git a/docs/future/FILEFMTS_HA.md b/docs/future/FILEFMTS_HA.md new file mode 100644 index 000000000..cb09009a1 --- /dev/null +++ b/docs/future/FILEFMTS_HA.md @@ -0,0 +1,53 @@ +--------A-HA-------------------------------- +HA files (not to be confused with HamarSoft's HAP files [3]) contain a +small archive header with a word count of the number of files in the +archive. The constituent files stored sequentially with a header followed +by the compressed data, as is with most archives. + +The main file header is formatted as follows: +OFFSET Count TYPE Description +0000h 2 char ID='HA' +0002h 1 word Number of files in archive + +Every compressed file has a header before it, like this : + +OFFSET Count TYPE Description +0000h 1 byte Version & compression type +0001h 1 dword Compressed file size +0005h 1 dword Original file size +0009h 1 dword CCITT CRC-32 (same as ZModem/PkZIP) +000Dh 1 dword File time-stamp (Unix format) + ? ? char ASCIIZ pathname + ? ? char ASCIIZ filename +????h 1 byte Length of machine specific information + ? byte Machine specific information + +Note that the path separator for pathnames is the 0FFh (255) character. + +The high nybble of the version & compression type field contains the +version information (0=HA 0.98), the low nybble is the compression type : + +(Table 0012) +HA compression types + 0 "CPY" File is stored (no compression) + 1 "ASC" Default compression method, using a sliding + window dictionary with an arithmetic coder. + 2 "HSC" Compression using a "finite context [sic] + model and arithmetic coder" + 14 "DIR" Directory entry + 15 "SPECIAL" Used with HA 0.99B (?) + + +Machine specific information known: + + 1 byte Machine type (Host-OS) + + 1 = MS DOS + 2 = Linux (Unix) + + ? bytes Information (currently only file-attribute info) + +EXTENSION:HA +OCCURENCES:PC, Linux +PROGRAMS:HA +REFERENCE: diff --git a/docs/future/FILEFMTS_HYP.md b/docs/future/FILEFMTS_HYP.md new file mode 100644 index 000000000..671f8c536 --- /dev/null +++ b/docs/future/FILEFMTS_HYP.md @@ -0,0 +1,23 @@ +--------A-HYP------------------------------- +The Hyper archiver is a very fast compression program by P. Sawatzki and K.P. +Nischke, which uses LZW compression techniques for compression. It is not very +widespread - in fact, I've yet to see a package distributed in this format. + +OFFSET Count TYPE Description +0000h 1 byte ID=1Ah +0001h 2 char Compression method + "HP" - compressed + "ST" - stored +0003h 1 byte Version file was compressed by in BCD +0004h 1 dword Compressed file size +0008h 1 dword Original file size +000Ch 1 dword MS-DOS date and time of file (see table 0009) +0010h 1 dword CRC-32 of file +0014h 1 byte MS-DOS file attribute +0015h 1 byte Length of filename + ="LEN" +0016h "LEN" char Filename + +EXTENSION:HYP +OCCURENCES:PC +PROGRAMS:HYPER.EXE diff --git a/docs/future/FILEFMTS_Introduction.md b/docs/future/FILEFMTS_Introduction.md new file mode 100644 index 000000000..2a4cd1ba9 --- /dev/null +++ b/docs/future/FILEFMTS_Introduction.md @@ -0,0 +1,137 @@ +File format list Release 3.00 Last change 02/04/96 +This compilation is Copyright (c) 1994,2002 Max Maischein +--------!-CONTACT_INFO---------------------- +If you notice any mistakes or omissions, please let me know! It is only +with YOUR help that the list can continue to grow. Please send +all changes to me rather than distributing a modified version of the list. + +This file has been authored in the style of the INTERxxy.* file list +by Ralf Brown, and uses almost the same format. + +Please read the file FILEFMTS.1ST before asking me any questions. You may find +that they have already been addressed. + + Max Maischein + +corion@corion.net +Corion on #coders@IRC +--------!-DISCLAIMER------------------------ +DISCLAIMER: THIS MATERIAL IS PROVIDED "AS IS". I verify the information +contained in this list to the best of my ability, but I cannot be held +responsible for any problems caused by use or misuse of the information, +especially for those file formats foreign to the PC, like AMIGA or SUN file +formats. If an information it is marked "guesswork" or undocumented, you +should check it carefully to make sure your program will not break with +an unexpected value (and please let me know whether or not it works +the same way). + +Information marked with "???" is known to be incomplete or guesswork. + +Some file formats were not released by their creators, others are regarded +as proprietary, which means that if your programs deal with them, you might +be looking for trouble. I don't care about this. +--------!-FLAGS----------------------------- +One or more letters may follow the file format ID; they have the following +meanings: + Cx - Charset used : + 7 - Unix 7-bit characters + A - Amiga charset (if there is one) + E - EBDIC character format + U - Unicode character set + W - Windows char set + Default is the 8-Bit IBM PC-II Charset. Note that Microsoft + introduced codepages which might be relevant with other + programs. + G - guesswork, incomplete, unreliable etc. + M - Motorola byte order + Default is Intel byte order + O - obsolete, valid only for version noted below + X - Synonym topic. See topic named under see also. +--------!-CATEGORIES------------------------ +The ninth column of the divider line preceding an entry usually contains a +classification code for the application that uses those files. + +The codes currently in use are: + ! - User information ( not really a file format ) + A - Archives (ARC,LZH,ZIP,...) + a - Animations (CEL, FLI, FLT,...) + B - Binary files for compilers etc. (OBJ,TPU) + H - Help file (HLP,NG) + I - Images, bit maps (GIF,BMP,TIFF,...) + D - Data support files (CPI,FON,...) + E - Executable files (EXE,PIF) + f - Generic file format. RIFF and IFF are generic file formats. + F - Font files (TTF) + G - General graphics file + M - Module music file (MIDI,MOD,S3M,...) + R - Resource data files (RES) + S - Sound files (WAV,VOC,ZYX) + T - Text files (DOC,TXT) + W - Spreadsheet and related (WKS) + X - Database files (DBF) +--------!-FIELDS---------------------------- +After a format description, you will sometimes find other keywords. The +meanings of these are : + EXTENSION: + This is the default extension of files of the given type. + On DOS systems, most files have a 3 letter extension. + On Amiga systems, the files are prefixed with something. + The DOS extensions are all uppercase, extensions for other systems + are in lower case chars. On other systems, which do not have the con- + cept of extensions, as the MAC, this is the file type. + OCCURENCES: + Where you are likely to encounter those files. This specifies + machines (like PC,AMIGA) or operating systems (like UNIX). + PROGRAMS: + Programs which either create, use or convert files of this format. + Some might be used for validation or conversion. + REFERENCE: + A reference to a file or an article in a magazine which is mandatory + or recommended for further understanding of the matter. + SEE ALSO: + A cross reference to a topic which might be interesting as well. + VALIDATION: + Methods to validate that the file you have is not corrupt. Normally + this is a method to check the theoretical file size against the + real filesize. Some file formats allow no reliable validation. +--------!-FORMAT---------------------------- + The block oriented files are organized in some other fashion, since the + order of blocks is at best marginally obligatory. + + Each block type starts with the block ID (eg. RIFFblock for a RIFF file) and + in square brackets the character value of the ID field (eg. [WAVE] for RIFF + WAVe sound files). The block itself is descripted in the format description, + that means you will have to look after RIFF or FORM. In the record + description, the header information is omitted ! + + If a record is descripted, the record ends when the next offset is given. + + Bitmapped values have a description for each bit. The value left of the + slash ("/") is for the bit not set (=0), the right sided value applies + if the bit is set. + + A note on the tables section. The tables were added as they were introduced + into Ralf Browns interrupt list - so not everything was pressed into a table. + The tables (should) have unique numbers, but they sure are out of order ! +--------!-MACHINES-------------------------- + Machines that use Intel byte ordering + PC + Machines that use Motorola byte ordering + AMIGA, ATARI ST, MAC, SUN +--------!-HISTORY--------------------------- +History is kept within this file for convenience whilst editing ... +Date format is european/german, just for my convenience. + +Date Who What +14.03.95 MM Introduced tables + Last table number=0012 +05.06.95 MM + PTM format +25.07.95 MM + PIF format + + Paradox format description +11.08.95 MM + MS Compress variants +18.11.95 MM + ARC enhancements, caveats + + HA files +22.11.95 MM + Parts of the .CRD files +01.02.96 MM + PNG structure +02.02.96 MM + More on JPEG + + TARGA entry created diff --git a/docs/future/FILEFMTS_LBR.md b/docs/future/FILEFMTS_LBR.md new file mode 100644 index 000000000..9f5d43136 --- /dev/null +++ b/docs/future/FILEFMTS_LBR.md @@ -0,0 +1,44 @@ +LBR +=== + +The LBR files consist of a direcotry and one or more "members". The directory +contains from 4 to 256 entries and each entry describes one member. +The first directory entry describes the directory itself. All space allocations +are in terms of sectors, where a sector is 128 bytes long. Four directory +entries fit in one sector thus the number of directory entries is always evenly +divisible by 4. Different types of LBR files exist, all versions are discussed +here, the directory entry looks like this : + +``` +OFFSET Count TYPE Description +0000h 1 byte File status : + 0 - active + 254 - deleted + 255 - free +0001h 11 char File name in FCB format (8/3, blank padded), + directory name is blanks for old LU, + ID='********DIR' + for LUPC +000Ch 1 word Offset to file data in sectors +000Eh 1 word Length of stored data in sectors + +For the LUPC program, the remaining 16 bytes are used like this : +OFFSET Count TYPE Description +0000h 8 char ASCII date of creation (MM/DD/YY) +0008h 8 char ASCII time of creation (HH:MM:SS) + +For the LU86 program, the remaining 16 bytes are used like this : +OFFSET Count TYPE Description +0000h 1 word CRC-16 or 0 +0002h 1 word Creation date in CP/M format +0004h 1 word Creation time in DOS format +0006h 1 word Date of last modification, CP/M format +0008h 1 word Time of last modification, DOS format +000Ah 1 byte Number of bytes in last sector +000Bh 5 byte reserved (0) + +EXTENSION:LBR +OCCURENCES:PC,CP/M +PROGRAMS:LU.COM, LUU.COM, LU86.COM +SEE ALSO: +``` diff --git a/docs/future/FILEFMTS_LZH.md b/docs/future/FILEFMTS_LZH.md new file mode 100644 index 000000000..8b0264b11 --- /dev/null +++ b/docs/future/FILEFMTS_LZH.md @@ -0,0 +1,42 @@ +LZH +=== + +The LHArc/LHA archiver is a multi platform archiver made by Haruyasu Yoshizaki, +which has a relatively good compression. It uses more or less the same +technology like the ZIP programs by Phil Katz. There was a hack named "ICE", +which had only the graphic characters displayed on decompression changed. + +``` +OFFSET Count TYPE Description +0000h 1 byte Size of archived file header +0001h 1 byte Checksum of remaining bytes +0002h 3 char ID='-lh' + ID='-lz' +0005h 1 char Compression methods used (see table 0005) +0006h 1 char ID='-' +0007h 1 dword Compressed size +000Bh 1 dword Uncompressed size +000Fh 1 dword Original file date/time (see table 0009) +0013h 1 word File attribute +0015h 1 byte Filename / path length in bytes + ="LEN" +0016h "LEN" char Filename / path +0018h 1 word CRC-16 of original file ++"LEN" + +(Table 0005) +LHArc compression types + "0" - No compression + "1" - LZW, 4K buffer, Huffman for upper 6 bits of position + "2" - unknown + "3" - unknown + "4" - LZW, Arithmetic Encoding + "5" - LZW, Arithmetic Encoding + "s" - LHa 2.x archive? + "\" - LHa 2.x archive? + "d" - LHa 2.x archive? + +EXTENSION:LZH,ICE +OCCURENCES:PC +PROGRAMS:LHArc.EXE, LHA.EXE +``` diff --git a/docs/future/FILEFMTS_ZOO.md b/docs/future/FILEFMTS_ZOO.md new file mode 100644 index 000000000..5f3799c08 --- /dev/null +++ b/docs/future/FILEFMTS_ZOO.md @@ -0,0 +1,40 @@ +--------A-ZOO------------------------------- +The ZOO archive program by Raoul Dhesi is a file compression program now +superceeded in both compression and speed by most other compression programs. +The archive header looks like this : +OFFSET Count TYPE Description +0000h 20 char Archive header text, ^Z terminated, null padded +0014h 1 dword ID=0FDC4A7DCh +0018h 1 dword Offset of first file in archive +001Ch 1 dword Offset of ???? +0020h 1 byte Version archive was made by +0021h 1 byte Minimum version needed to extract + +Each stored file has its own header, which looks like this : +OFFSET Count TYPE Description +0000h 1 dword ID=0FDC4A7DCh +0004h 1 byte Type of directory entry +0005h 1 byte Compression method : + 0 - stored + 1 - Crunched : LZW, 4K buffer, + var len (9-13 bits) +0006h 1 dword Offset of next directory entry +000Ah 1 dword Offset of next header +000Dh 1 word Original date / time of file (see table 0009) +0012h 1 word CRC-16 of file +0014h 1 dword Uncompressed size of file +0018h 1 dword Compressed size of file +001Ch 1 byte Version this file was compressed by +001Dh 1 byte Minimum version needed to extract +001Eh 1 byte Deleted flag + 0 - file in archive + 1 - file is considered deleted +001Fh 1 dword Offset of comment field, 0 if none +0023h 1 word Length of comment field +0025h ? char ASCIIZ path / filename + +EXTENSION:ZOO +OCCURENCES:PC +PROGRAMS:ZOO.EXE +REFERENCE: +VALIDATION: diff --git a/docs/future/FILE_ID.DIZ b/docs/future/FILE_ID.DIZ new file mode 100644 index 000000000..0096a2aa2 --- /dev/null +++ b/docs/future/FILE_ID.DIZ @@ -0,0 +1,11 @@ +File formats Release #03 12/02 + +A documentation of over 100 file +formats covering : + +Modules : (MOD,S3M,669,XM,etc.) +Images : (GIF,LBM,IFF,PCX,etc.) +Binaries: (COM,EXE,Windows,etc.) +Archives: (ARJ,LHA,ZIP,etc.) +Sound : (VOC,WAV,ZYX,.AU,etc.) +DataBase: (DBF) \ No newline at end of file diff --git a/docs/future/README.md b/docs/future/README.md new file mode 100644 index 000000000..7ddb6b155 --- /dev/null +++ b/docs/future/README.md @@ -0,0 +1,170 @@ +Future Work +=========== + +C# implementation of older archive file formats. + +Documentation from http://www.corion.net/fileformats/index.html + +File format list Release 3.00 Last change 02/04/96 +This compilation is Copyright (c) 1994,2002 Max Maischein + +## CONTACT_INFO + +If you notice any mistakes or omissions, please let me know! It is only +with YOUR help that the list can continue to grow. Please send +all changes to me rather than distributing a modified version of the list. + +This file has been authored in the style of the INTERxxy.* file list +by Ralf Brown, and uses almost the same format. + +Please read the file FILEFMTS.1ST before asking me any questions. You may find +that they have already been addressed. + + Max Maischein + +corion@corion.net +Corion on #coders@IRC + +## DISCLAIMER + +DISCLAIMER: THIS MATERIAL IS PROVIDED "AS IS". I verify the information +contained in this list to the best of my ability, but I cannot be held +responsible for any problems caused by use or misuse of the information, +especially for those file formats foreign to the PC, like AMIGA or SUN file +formats. If an information it is marked "guesswork" or undocumented, you +should check it carefully to make sure your program will not break with +an unexpected value (and please let me know whether or not it works +the same way). + +Information marked with "???" is known to be incomplete or guesswork. + +Some file formats were not released by their creators, others are regarded +as proprietary, which means that if your programs deal with them, you might +be looking for trouble. I don't care about this. + +## FLAGS + +One or more letters may follow the file format ID; they have the following +meanings: + +``` + Cx - Charset used : + 7 - Unix 7-bit characters + A - Amiga charset (if there is one) + E - EBDIC character format + U - Unicode character set + W - Windows char set + Default is the 8-Bit IBM PC-II Charset. Note that Microsoft + introduced codepages which might be relevant with other + programs. + G - guesswork, incomplete, unreliable etc. + M - Motorola byte order + Default is Intel byte order + O - obsolete, valid only for version noted below + X - Synonym topic. See topic named under see also. +``` + +## CATEGORIES + +The ninth column of the divider line preceding an entry usually contains a +classification code for the application that uses those files. + +The codes currently in use are: +``` +! - User information ( not really a file format ) +A - Archives (ARC,LZH,ZIP,...) +a - Animations (CEL, FLI, FLT,...) +B - Binary files for compilers etc. (OBJ,TPU) +H - Help file (HLP,NG) +I - Images, bit maps (GIF,BMP,TIFF,...) +D - Data support files (CPI,FON,...) +E - Executable files (EXE,PIF) +f - Generic file format. RIFF and IFF are generic file formats. +F - Font files (TTF) +G - General graphics file +M - Module music file (MIDI,MOD,S3M,...) +R - Resource data files (RES) +S - Sound files (WAV,VOC,ZYX) +T - Text files (DOC,TXT) +W - Spreadsheet and related (WKS) +X - Database files (DBF) +``` + +## FIELDS + +After a format description, you will sometimes find other keywords. The +meanings of these are : +### EXTENSION: + This is the default extension of files of the given type. + On DOS systems, most files have a 3 letter extension. + On Amiga systems, the files are prefixed with something. + The DOS extensions are all uppercase, extensions for other systems + are in lower case chars. On other systems, which do not have the con- + cept of extensions, as the MAC, this is the file type. +### OCCURENCES: +Where you are likely to encounter those files. This specifies +machines (like PC,AMIGA) or operating systems (like UNIX). +### PROGRAMS: +Programs which either create, use or convert files of this format. +Some might be used for validation or conversion. +### REFERENCE: +A reference to a file or an article in a magazine which is mandatory +or recommended for further understanding of the matter. +### SEE ALSO: +A cross reference to a topic which might be interesting as well. +### VALIDATION: +Methods to validate that the file you have is not corrupt. Normally +this is a method to check the theoretical file size against the +real filesize. Some file formats allow no reliable validation. + +## FORMAT + +The block oriented files are organized in some other fashion, since the +order of blocks is at best marginally obligatory. + +Each block type starts with the block ID (eg. RIFFblock for a RIFF file) and +in square brackets the character value of the ID field (eg. [WAVE] for RIFF +WAVe sound files). The block itself is descripted in the format description, +that means you will have to look after RIFF or FORM. In the record +description, the header information is omitted ! + +If a record is descripted, the record ends when the next offset is given. + +Bitmapped values have a description for each bit. The value left of the +slash ("/") is for the bit not set (=0), the right sided value applies +if the bit is set. + +A note on the tables section. The tables were added as they were introduced +into Ralf Browns interrupt list - so not everything was pressed into a table. +The tables (should) have unique numbers, but they sure are out of order ! + +## MACHINES + +Machines that use Intel byte ordering +* PC + +Machines that use Motorola byte ordering +* AMIGA +* ATARI ST +* MAC +* SUN + +## HISTORY + +History is kept within this file for convenience whilst editing ... +Date format is european/german, just for my convenience. +``` +Date Who What +14.03.95 MM Introduced tables + Last table number=0012 +05.06.95 MM + PTM format +25.07.95 MM + PIF format + + Paradox format description +11.08.95 MM + MS Compress variants +18.11.95 MM + ARC enhancements, caveats + + HA files +22.11.95 MM + Parts of the .CRD files +01.02.96 MM + PNG structure +02.02.96 MM + More on JPEG + + TARGA entry created +``` diff --git a/docs/future/tar_15.html b/docs/future/tar_15.html new file mode 100644 index 000000000..c24f41e9e --- /dev/null +++ b/docs/future/tar_15.html @@ -0,0 +1,516 @@ + + + + + + +GNU tar 1.28: E. Genfile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
[ < ][ > ]   [ << ][ Up ][ >> ]         [Top][Contents][Index][ ? ]
+

E. Genfile

+ + +

This appendix describes genfile, an auxiliary program +used in the GNU tar testsuite. If you are not interested in developing +GNU tar, skip this appendix. +

+

Initially, genfile was used to generate data files for +the testsuite, hence its name. However, new operation modes were being +implemented as the testsuite grew more sophisticated, and now +genfile is a multi-purpose instrument. +

+

There are three basic operation modes: +

+
+
File Generation
+

This is the default mode. In this mode, genfile +generates data files. +

+
+
File Status
+

In this mode genfile displays status of specified files. +

+
+
Synchronous Execution.
+

In this mode genfile executes the given program with +`--checkpoint' option and executes a set of actions when +specified checkpoints are reached. +

+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + +
[ < ][ > ]   [ << ][ Up ][ >> ]         [Top][Contents][Index][ ? ]
+

E.1 Generate Mode

+ +

In this mode genfile creates a data file for the test +suite. The size of the file is given with the `--length' +(`-l') option. By default the file contents is written to the +standard output, this can be changed using `--file' +(`-f') command line option. Thus, the following two commands +are equivalent: +

+
 
genfile --length 100 > outfile
+genfile --length 100 --file outfile
+
+

If `--length' is not given, genfile will +generate an empty (zero-length) file. +

+ +

The command line option `--seek=N' istructs genfile +to skip the given number of bytes (N) in the output file before +writing to it. It is similar to the `seek=N' of the +dd utility. +

+ +

You can instruct genfile to create several files at one +go, by giving it `--files-from' (`-T') option followed +by a name of file containing a list of file names. Using dash +(`-') instead of the file name causes genfile to read +file list from the standard input. For example: +

+
 
# Read file names from file `file.list'
+genfile --files-from file.list
+# Read file names from standard input
+genfile --files-from -
+
+ +

The list file is supposed to contain one file name per line. To +use file lists separated by ASCII NUL character, use `--null' +(`-0') command line option: +

+
 
genfile --null --files-from file.list
+
+ +

The default data pattern for filling the generated file consists +of first 256 letters of ASCII code, repeated enough times to fill the +entire file. This behavior can be changed with `--pattern' +option. This option takes a mandatory argument, specifying pattern +name to use. Currently two patterns are implemented: +

+
+
`--pattern=default'
+

The default pattern as described above. +

+
+
`--pattern=zero'
+

Fills the file with zeroes. +

+
+ +

If no file name was given, the program exits with the code +0. Otherwise, it exits with 0 only if it was able to +create a file of the specified length. +

+ + +

Special option `--sparse' (`-s') instructs +genfile to create a sparse file. Sparse files consist of +data fragments, separated by holes or blocks of zeros. On +many operating systems, actual disk storage is not allocated for +holes, but they are counted in the length of the file. To create a +sparse file, genfile should know where to put data fragments, +and what data to use to fill them. So, when `--sparse' is given +the rest of the command line specifies a so-called file map. +

+

The file map consists of any number of fragment +descriptors. Each descriptor is composed of two values: a number, +specifying fragment offset from the end of the previous fragment or, +for the very first fragment, from the beginning of the file, and +contents string, i.e., a string of characters, specifying the +pattern to fill the fragment with. File offset can be suffixed with +the following quantifiers: +

+
+
`k'
+
`K'
+

The number is expressed in kilobytes. +

+
`m'
+
`M'
+

The number is expressed in megabytes. +

+
`g'
+
`G'
+

The number is expressed in gigabytes. +

+
+ +

For each letter in contents string genfile will generate +a block of data, filled with this letter and will write it to +the fragment. The size of block is given by `--block-size' +option. It defaults to 512. Thus, if the string consists of n +characters, the resulting file fragment will contain +n*block-size of data. +

+

Last fragment descriptor can have only file offset part. In this +case genfile will create a hole at the end of the file up to +the given offset. +

+

For example, consider the following invocation: +

+
 
genfile --sparse --file sparsefile 0 ABCD 1M EFGHI 2000K
+
+ +

It will create 3101184-bytes long file of the following structure: +

+ + + + + + +

Offset

Length

Contents +

0

4*512=2048

Four 512-byte blocks, filled with +letters `A', `B', `C' and `D'. +

2048

1046528

Zero bytes +

1050624

5*512=2560

Five blocks, filled with letters +`E', `F', `G', `H', `I'. +

1053184

2048000

Zero bytes +

+ +

The exit code of genfile --status command is 0 +only if created file is actually sparse. +

+
+ + + + + + + + + + + + + + + + + +
[ < ][ > ]   [ << ][ Up ][ >> ]         [Top][Contents][Index][ ? ]
+

E.2 Status Mode

+ +

In status mode, genfile prints file system status for +each file specified in the command line. This mode is toggled by +`--stat' (`-S') command line option. An optional argument to this +option specifies output format: a comma-separated list of +struct stat fields to be displayed. This list can contain +following identifiers: +

+
+
name
+

The file name. +

+
+
dev
+
st_dev
+

Device number in decimal. +

+
+
ino
+
st_ino
+

Inode number. +

+
+
mode[.number]
+
st_mode[.number]
+
+

See Should we also support `%' notations as in stat(1)? +

+ +

File mode in octal. Optional number specifies octal mask to +be applied to the mode before outputting. For example, --stat +mode.777 will preserve lower nine bits of it. Notice, that you can +use any punctuation character in place of `.'. +

+
+
nlink
+
st_nlink
+

Number of hard links. +

+
+
uid
+
st_uid
+

User ID of owner. +

+
+
gid
+
st_gid
+

Group ID of owner. +

+
+
size
+
st_size
+

File size in decimal. +

+
+
blksize
+
st_blksize
+

The size in bytes of each file block. +

+
+
blocks
+
st_blocks
+

Number of blocks allocated. +

+
+
atime
+
st_atime
+

Time of last access. +

+
+
mtime
+
st_mtime
+

Time of last modification +

+
+
ctime
+
st_ctime
+

Time of last status change +

+
+
sparse
+

A boolean value indicating whether the file is `sparse'. +

+
+ +

Modification times are displayed in UTC as +UNIX timestamps, unless suffixed with `H' (for +"human-readable"), as in `ctimeH', in which case usual +tar tv output format is used. +

+

The default output format is: `name,dev,ino,mode, +nlink,uid,gid,size,blksize,blocks,atime,mtime,ctime'. +

+

For example, the following command will display file names and +corresponding times of last access for each file in the current working +directory: +

+
 
genfile --stat=name,atime *
+
+
+ + + + + + + + + + + + + + + + + +
[ < ][ > ]   [ << ][ Up ][ >> ]         [Top][Contents][Index][ ? ]
+

E.3 Exec Mode

+ +

This mode is designed for testing the behavior of paxutils +commands when some of the files change during archiving. It is an +experimental mode. +

+

The `Exec Mode' is toggled by `--run' command line +option (or its alias `-r'). The non-optional arguments to +getopt give the command line to be executed. Normally, +it should contain at least the `--checkpoint' option. +

+

A set of options is provided for defining checkpoint values and +actions to be executed upon reaching them. Checkpoint values are +introduced with the `--checkpoint' command line +option. Argument to this option is the number of checkpoint in decimal. +

+

Any number of actions may be specified after a +checkpoint. Available actions are +

+
+
`--cut file'
+
`--truncate file'
+

Truncate file to the size specified by previous +`--length' option (or 0, if it is not given). +

+
+
`--append file'
+

Append data to file. The size of data and its pattern are +given by previous `--length' and `pattern' options. +

+
+
`--touch file'
+

Update the access and modification times of file. These +timestamps are changed to the current time, unless `--date' +option was given, in which case they are changed to the specified +time. Argument to `--date' option is a date specification in +an almost arbitrary format (see section Date input formats). +

+
+
`--exec command'
+

Execute given shell command. +

+
+
`--unlink file'
+

Unlink the file. +

+
+ +

Option `--verbose' instructs genfile to print on +standard output notifications about checkpoints being executed and to +verbosely describe exit status of the command. +

+

While the command is being executed its standard output remains +connected to descriptor 1. All messages it prints to file descriptor +2, except checkpoint notifications, are forwarded to standard +error. +

+

Genfile exits with the exit status of the executed command. +

+

For compatibility with previous genfile versions, the +`--run' option takes an optional argument. If used this way, +its argument supplies the command line to be executed. There should +be no non-optional arguments in the genfile command line. +

+

The actual command line is constructed by inserting +the `--checkpoint' option between the command name and its +first argument (if any). Due to this, the argument to `--run' +may not use traditional tar option syntax, i.e., the +following is wrong: +

+
 
# Wrong!
+genfile --run='tar cf foo bar'
+
+ + +

Use the following syntax instead: +

+
 
genfile --run='tar -cf foo bar' actions...
+
+

The above command line is equivalent to +

+
 
genfile actions... -- tar -cf foo bar
+
+

Notice, that the use of compatibility mode is deprecated. +

+
+ + + + + + + + + + + + +
[ << ][ >> ]           [Top][Contents][Index][ ? ]
+

+ + This document was generated on July, 28 2014 using texi2html 1.76. + +
+ +

+ + diff --git a/docs/help/.gitignore b/docs/help/.gitignore new file mode 100644 index 000000000..4378419e7 --- /dev/null +++ b/docs/help/.gitignore @@ -0,0 +1,9 @@ +############### +# folder # +############### +/**/DROP/ +/**/TEMP/ +/**/packages/ +/**/bin/ +/**/obj/ +_site diff --git a/docs/help/BuildingHelpInfo.txt b/docs/help/BuildingHelpInfo.txt new file mode 100644 index 000000000..119768ef7 --- /dev/null +++ b/docs/help/BuildingHelpInfo.txt @@ -0,0 +1,19 @@ +# Basics + +You need DocFx: + +https://dotnet.github.io/docfx/tutorial/docfx_getting_started.html#2-use-docfx-as-a-command-line-tool + +You have to run it using the "Developer Command Prompt for VS 2017" + + +# Building + +In this folder, run "docfx metadata" to build the API documentation (/api folder) + +In this folder, run "serve.bat" to build & serve the documenation for local testing + + +# Publishing + +The _site folder is to be copied to gh-pages branch for publishing \ No newline at end of file diff --git a/docs/help/api/.gitignore b/docs/help/api/.gitignore new file mode 100644 index 000000000..da7c71b83 --- /dev/null +++ b/docs/help/api/.gitignore @@ -0,0 +1,4 @@ +############### +# temp file # +############### +*.yml diff --git a/docs/help/api/index.md b/docs/help/api/index.md new file mode 100644 index 000000000..9e64a4d16 --- /dev/null +++ b/docs/help/api/index.md @@ -0,0 +1,3 @@ +# API Documentation + +Please select class / method / property from the tree on the left side to learn more. diff --git a/docs/help/api/toc.yml b/docs/help/api/toc.yml new file mode 100644 index 000000000..2cc204bde --- /dev/null +++ b/docs/help/api/toc.yml @@ -0,0 +1,244 @@ +### YamlMime:TableOfContent +- uid: ICSharpCode.SharpZipLib + name: ICSharpCode.SharpZipLib + items: + - uid: ICSharpCode.SharpZipLib.SharpZipBaseException + name: SharpZipBaseException +- uid: ICSharpCode.SharpZipLib.BZip2 + name: ICSharpCode.SharpZipLib.BZip2 + items: + - uid: ICSharpCode.SharpZipLib.BZip2.BZip2 + name: BZip2 + - uid: ICSharpCode.SharpZipLib.BZip2.BZip2Exception + name: BZip2Exception + - uid: ICSharpCode.SharpZipLib.BZip2.BZip2InputStream + name: BZip2InputStream + - uid: ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream + name: BZip2OutputStream +- uid: ICSharpCode.SharpZipLib.Checksum + name: ICSharpCode.SharpZipLib.Checksum + items: + - uid: ICSharpCode.SharpZipLib.Checksum.Adler32 + name: Adler32 + - uid: ICSharpCode.SharpZipLib.Checksum.BZip2Crc + name: BZip2Crc + - uid: ICSharpCode.SharpZipLib.Checksum.Crc32 + name: Crc32 + - uid: ICSharpCode.SharpZipLib.Checksum.IChecksum + name: IChecksum +- uid: ICSharpCode.SharpZipLib.Core + name: ICSharpCode.SharpZipLib.Core + items: + - uid: ICSharpCode.SharpZipLib.Core.CompletedFileHandler + name: CompletedFileHandler + - uid: ICSharpCode.SharpZipLib.Core.DirectoryEventArgs + name: DirectoryEventArgs + - uid: ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler + name: DirectoryFailureHandler + - uid: ICSharpCode.SharpZipLib.Core.ExtendedPathFilter + name: ExtendedPathFilter + - uid: ICSharpCode.SharpZipLib.Core.FileFailureHandler + name: FileFailureHandler + - uid: ICSharpCode.SharpZipLib.Core.FileSystemScanner + name: FileSystemScanner + - uid: ICSharpCode.SharpZipLib.Core.INameTransform + name: INameTransform + - uid: ICSharpCode.SharpZipLib.Core.IScanFilter + name: IScanFilter + - uid: ICSharpCode.SharpZipLib.Core.NameAndSizeFilter + name: NameAndSizeFilter + - uid: ICSharpCode.SharpZipLib.Core.NameFilter + name: NameFilter + - uid: ICSharpCode.SharpZipLib.Core.PathFilter + name: PathFilter + - uid: ICSharpCode.SharpZipLib.Core.ProcessFileHandler + name: ProcessFileHandler + - uid: ICSharpCode.SharpZipLib.Core.ProgressEventArgs + name: ProgressEventArgs + - uid: ICSharpCode.SharpZipLib.Core.ProgressHandler + name: ProgressHandler + - uid: ICSharpCode.SharpZipLib.Core.ScanEventArgs + name: ScanEventArgs + - uid: ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs + name: ScanFailureEventArgs + - uid: ICSharpCode.SharpZipLib.Core.StreamUtils + name: StreamUtils + - uid: ICSharpCode.SharpZipLib.Core.WindowsPathUtils + name: WindowsPathUtils +- uid: ICSharpCode.SharpZipLib.Encryption + name: ICSharpCode.SharpZipLib.Encryption + items: + - uid: ICSharpCode.SharpZipLib.Encryption.PkzipClassic + name: PkzipClassic + - uid: ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged + name: PkzipClassicManaged +- uid: ICSharpCode.SharpZipLib.GZip + name: ICSharpCode.SharpZipLib.GZip + items: + - uid: ICSharpCode.SharpZipLib.GZip.GZip + name: GZip + - uid: ICSharpCode.SharpZipLib.GZip.GZipConstants + name: GZipConstants + - uid: ICSharpCode.SharpZipLib.GZip.GZipException + name: GZipException + - uid: ICSharpCode.SharpZipLib.GZip.GZipInputStream + name: GZipInputStream + - uid: ICSharpCode.SharpZipLib.GZip.GZipOutputStream + name: GZipOutputStream +- uid: ICSharpCode.SharpZipLib.Lzw + name: ICSharpCode.SharpZipLib.Lzw + items: + - uid: ICSharpCode.SharpZipLib.Lzw.LzwConstants + name: LzwConstants + - uid: ICSharpCode.SharpZipLib.Lzw.LzwException + name: LzwException + - uid: ICSharpCode.SharpZipLib.Lzw.LzwInputStream + name: LzwInputStream +- uid: ICSharpCode.SharpZipLib.Tar + name: ICSharpCode.SharpZipLib.Tar + items: + - uid: ICSharpCode.SharpZipLib.Tar.InvalidHeaderException + name: InvalidHeaderException + - uid: ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler + name: ProgressMessageHandler + - uid: ICSharpCode.SharpZipLib.Tar.TarArchive + name: TarArchive + - uid: ICSharpCode.SharpZipLib.Tar.TarBuffer + name: TarBuffer + - uid: ICSharpCode.SharpZipLib.Tar.TarEntry + name: TarEntry + - uid: ICSharpCode.SharpZipLib.Tar.TarException + name: TarException + - uid: ICSharpCode.SharpZipLib.Tar.TarHeader + name: TarHeader + - uid: ICSharpCode.SharpZipLib.Tar.TarInputStream + name: TarInputStream + - uid: ICSharpCode.SharpZipLib.Tar.TarInputStream.EntryFactoryAdapter + name: TarInputStream.EntryFactoryAdapter + - uid: ICSharpCode.SharpZipLib.Tar.TarInputStream.IEntryFactory + name: TarInputStream.IEntryFactory + - uid: ICSharpCode.SharpZipLib.Tar.TarOutputStream + name: TarOutputStream +- uid: ICSharpCode.SharpZipLib.Zip + name: ICSharpCode.SharpZipLib.Zip + items: + - uid: ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage + name: BaseArchiveStorage + - uid: ICSharpCode.SharpZipLib.Zip.CompressionMethod + name: CompressionMethod + - uid: ICSharpCode.SharpZipLib.Zip.DescriptorData + name: DescriptorData + - uid: ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage + name: DiskArchiveStorage + - uid: ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource + name: DynamicDiskDataSource + - uid: ICSharpCode.SharpZipLib.Zip.EncryptionAlgorithm + name: EncryptionAlgorithm + - uid: ICSharpCode.SharpZipLib.Zip.ExtendedUnixData + name: ExtendedUnixData + - uid: ICSharpCode.SharpZipLib.Zip.ExtendedUnixData.Flags + name: ExtendedUnixData.Flags + - uid: ICSharpCode.SharpZipLib.Zip.FastZip + name: FastZip + - uid: ICSharpCode.SharpZipLib.Zip.FastZip.ConfirmOverwriteDelegate + name: FastZip.ConfirmOverwriteDelegate + - uid: ICSharpCode.SharpZipLib.Zip.FastZip.Overwrite + name: FastZip.Overwrite + - uid: ICSharpCode.SharpZipLib.Zip.FastZipEvents + name: FastZipEvents + - uid: ICSharpCode.SharpZipLib.Zip.FileUpdateMode + name: FileUpdateMode + - uid: ICSharpCode.SharpZipLib.Zip.GeneralBitFlags + name: GeneralBitFlags + - uid: ICSharpCode.SharpZipLib.Zip.HostSystemID + name: HostSystemID + - uid: ICSharpCode.SharpZipLib.Zip.IArchiveStorage + name: IArchiveStorage + - uid: ICSharpCode.SharpZipLib.Zip.IDynamicDataSource + name: IDynamicDataSource + - uid: ICSharpCode.SharpZipLib.Zip.IEntryFactory + name: IEntryFactory + - uid: ICSharpCode.SharpZipLib.Zip.IStaticDataSource + name: IStaticDataSource + - uid: ICSharpCode.SharpZipLib.Zip.ITaggedData + name: ITaggedData + - uid: ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs + name: KeysRequiredEventArgs + - uid: ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage + name: MemoryArchiveStorage + - uid: ICSharpCode.SharpZipLib.Zip.NTTaggedData + name: NTTaggedData + - uid: ICSharpCode.SharpZipLib.Zip.RawTaggedData + name: RawTaggedData + - uid: ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource + name: StaticDiskDataSource + - uid: ICSharpCode.SharpZipLib.Zip.TestOperation + name: TestOperation + - uid: ICSharpCode.SharpZipLib.Zip.TestStatus + name: TestStatus + - uid: ICSharpCode.SharpZipLib.Zip.TestStrategy + name: TestStrategy + - uid: ICSharpCode.SharpZipLib.Zip.UseZip64 + name: UseZip64 + - uid: ICSharpCode.SharpZipLib.Zip.WindowsNameTransform + name: WindowsNameTransform + - uid: ICSharpCode.SharpZipLib.Zip.ZipConstants + name: ZipConstants + - uid: ICSharpCode.SharpZipLib.Zip.ZipEntry + name: ZipEntry + - uid: ICSharpCode.SharpZipLib.Zip.ZipEntryFactory + name: ZipEntryFactory + - uid: ICSharpCode.SharpZipLib.Zip.ZipEntryFactory.TimeSetting + name: ZipEntryFactory.TimeSetting + - uid: ICSharpCode.SharpZipLib.Zip.ZipException + name: ZipException + - uid: ICSharpCode.SharpZipLib.Zip.ZipExtraData + name: ZipExtraData + - uid: ICSharpCode.SharpZipLib.Zip.ZipFile + name: ZipFile + - uid: ICSharpCode.SharpZipLib.Zip.ZipFile.KeysRequiredEventHandler + name: ZipFile.KeysRequiredEventHandler + - uid: ICSharpCode.SharpZipLib.Zip.ZipInputStream + name: ZipInputStream + - uid: ICSharpCode.SharpZipLib.Zip.ZipNameTransform + name: ZipNameTransform + - uid: ICSharpCode.SharpZipLib.Zip.ZipOutputStream + name: ZipOutputStream + - uid: ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler + name: ZipTestResultHandler +- uid: ICSharpCode.SharpZipLib.Zip.Compression + name: ICSharpCode.SharpZipLib.Zip.Compression + items: + - uid: ICSharpCode.SharpZipLib.Zip.Compression.Deflater + name: Deflater + - uid: ICSharpCode.SharpZipLib.Zip.Compression.Deflater.CompressionLevel + name: Deflater.CompressionLevel + - uid: ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants + name: DeflaterConstants + - uid: ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine + name: DeflaterEngine + - uid: ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman + name: DeflaterHuffman + - uid: ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending + name: DeflaterPending + - uid: ICSharpCode.SharpZipLib.Zip.Compression.DeflateStrategy + name: DeflateStrategy + - uid: ICSharpCode.SharpZipLib.Zip.Compression.Inflater + name: Inflater + - uid: ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree + name: InflaterHuffmanTree + - uid: ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer + name: PendingBuffer +- uid: ICSharpCode.SharpZipLib.Zip.Compression.Streams + name: ICSharpCode.SharpZipLib.Zip.Compression.Streams + items: + - uid: ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream + name: DeflaterOutputStream + - uid: ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer + name: InflaterInputBuffer + - uid: ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream + name: InflaterInputStream + - uid: ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow + name: OutputWindow + - uid: ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator + name: StreamManipulator diff --git a/docs/help/articles/intro.md b/docs/help/articles/intro.md new file mode 100644 index 000000000..8697295a0 --- /dev/null +++ b/docs/help/articles/intro.md @@ -0,0 +1,3 @@ +# Articles + +FAQ and walk-through-sample explanations are provided in the [Wiki](https://github.com/icsharpcode/SharpZipLib/wiki) diff --git a/docs/help/articles/toc.yml b/docs/help/articles/toc.yml new file mode 100644 index 000000000..ff89ef1fe --- /dev/null +++ b/docs/help/articles/toc.yml @@ -0,0 +1,2 @@ +- name: Introduction + href: intro.md diff --git a/docs/help/docfx.json b/docs/help/docfx.json new file mode 100644 index 000000000..173bb4360 --- /dev/null +++ b/docs/help/docfx.json @@ -0,0 +1,78 @@ +{ + "metadata": [ + { + "src": [ + { + "cwd": "../../src/", + "files": [ + "ICSharpCode.SharpZipLib/**.csproj" + ], + "exclude": [ + "**/obj/**", + "**/bin/**", + "_site/**" + ] + } + ], + "dest": "api" + } + ], + "build": { + "content": [ + { + "files": [ + "api/**.yml", + "api/index.md" + ] + }, + { + "files": [ + "articles/**.md", + "articles/**/toc.yml", + "toc.yml", + "*.md" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + } + ], + "resource": [ + { + "files": [ + "images/**" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + } + ], + "overwrite": [ + { + "files": [ + "apidoc/**.md" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + } + ], + "globalMetadata": { + "_appTitle": "SharpZipLib Help", + "_appFooter": "Copyright © 2000-2017 SharpZipLib Contributors" + }, + "dest": "_site", + "globalMetadataFiles": [], + "fileMetadataFiles": [], + "template": [ + "default" + ], + "postProcessors": [], + "noLangKeyword": false, + "keepFileLink": false, + "cleanupCacheHistory": false + } +} \ No newline at end of file diff --git a/docs/help/index.md b/docs/help/index.md new file mode 100644 index 000000000..10f55e5a3 --- /dev/null +++ b/docs/help/index.md @@ -0,0 +1,8 @@ +# Help Homepage. + +Looking for the [API Documentation](api/index.md)? + +Looking for the [source code](https://github.com/icsharpcode/SharpZipLib)? + +Want to report a bug, suggest a new feature, ask a deep technical question? [Issues](https://github.com/icsharpcode/SharpZipLib/issues) + diff --git a/docs/help/serve.bat b/docs/help/serve.bat new file mode 100644 index 000000000..3a6bafe3b --- /dev/null +++ b/docs/help/serve.bat @@ -0,0 +1 @@ +docfx docfx.json --serve \ No newline at end of file diff --git a/docs/help/toc.yml b/docs/help/toc.yml new file mode 100644 index 000000000..59f801047 --- /dev/null +++ b/docs/help/toc.yml @@ -0,0 +1,5 @@ +- name: Articles + href: articles/ +- name: Api Documentation + href: api/ + homepage: api/index.md diff --git a/docs/nunit3-test-results-debug.xml b/docs/nunit3-test-results-debug.xml new file mode 100644 index 000000000..ffd4ea06d --- /dev/null +++ b/docs/nunit3-test-results-debug.xml @@ -0,0 +1,894 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/nunit3-test-results-release.xml b/docs/nunit3-test-results-release.xml new file mode 100644 index 000000000..ccc3edc47 --- /dev/null +++ b/docs/nunit3-test-results-release.xml @@ -0,0 +1,800 @@ + + + + + + ICSharpCode.SharpZipLib.Tests.BZip2.BZip2Suite.BasicRoundTrip + ICSharpCode.SharpZipLib.Tests.BZip2.BZip2Suite.CreateEmptyArchive + ICSharpCode.SharpZipLib.Tests.Base.InflaterDeflaterTestSuite.CloseDeflatorWithNestedUsing + ICSharpCode.SharpZipLib.Tests.Base.InflaterDeflaterTestSuite.CloseInflatorWithNestedUsing + ICSharpCode.SharpZipLib.Tests.Base.InflaterDeflaterTestSuite.DeflatorStreamOwnership + ICSharpCode.SharpZipLib.Tests.Base.InflaterDeflaterTestSuite.InflateDeflateNonZlib + ICSharpCode.SharpZipLib.Tests.Base.InflaterDeflaterTestSuite.InflateDeflateZlib + ICSharpCode.SharpZipLib.Tests.Base.InflaterDeflaterTestSuite.InflatorStreamOwnership + ICSharpCode.SharpZipLib.Tests.Checksum.ChecksumTests.Adler_32 + ICSharpCode.SharpZipLib.Tests.Checksum.ChecksumTests.CRC_32 + ICSharpCode.SharpZipLib.Tests.Checksum.ChecksumTests.CRC_32_BZip2 + ICSharpCode.SharpZipLib.Tests.Core.Core.FilterQuoting + ICSharpCode.SharpZipLib.Tests.Core.Core.NullFilter + ICSharpCode.SharpZipLib.Tests.Core.Core.ValidFilter + ICSharpCode.SharpZipLib.Tests.GZip.GZipTestSuite.DelayedHeaderWriteNoData + ICSharpCode.SharpZipLib.Tests.GZip.GZipTestSuite.DelayedHeaderWriteWithData + ICSharpCode.SharpZipLib.Tests.GZip.GZipTestSuite.DoubleClose + ICSharpCode.SharpZipLib.Tests.GZip.GZipTestSuite.DoubleFooter + ICSharpCode.SharpZipLib.Tests.GZip.GZipTestSuite.InputStreamOwnership + ICSharpCode.SharpZipLib.Tests.GZip.GZipTestSuite.OutputStreamOwnership + ICSharpCode.SharpZipLib.Tests.GZip.GZipTestSuite.TestGZip + ICSharpCode.SharpZipLib.Tests.GZip.GZipTestSuite.WriteAfterClose + ICSharpCode.SharpZipLib.Tests.GZip.GZipTestSuite.WriteAfterFinish + ICSharpCode.SharpZipLib.Tests.LZW.LzwTestSuite.InputStreamOwnership + ICSharpCode.SharpZipLib.Tests.LZW.LzwTestSuite.ZeroLengthInputStream + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.BlockFactorHandling + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.Checksum + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.CloningAndUniqueness + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.EmptyTar + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.HeaderEquality + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.InputStreamOwnership + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.InvalidLinkName + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.InvalidMagic + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.InvalidModTime + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.InvalidName + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.InvalidSize + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.InvalidVersionName + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.OutputStreamOwnership + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.TrailerContainsNulls + ICSharpCode.SharpZipLib.Tests.Tar.TarTestSuite.UserAndGroupNames + ICSharpCode.SharpZipLib.Tests.TestSupport.ExerciseBuffer.Basic + ICSharpCode.SharpZipLib.Tests.TestSupport.ExerciseBuffer.Buffered + ICSharpCode.SharpZipLib.Tests.TestSupport.ExerciseBuffer.Threaded + ICSharpCode.SharpZipLib.Tests.Zip.FastZipHandling.Basics + ICSharpCode.SharpZipLib.Tests.Zip.FastZipHandling.Encryption + ICSharpCode.SharpZipLib.Tests.Zip.FastZipHandling.ExtractEmptyDirectories + ICSharpCode.SharpZipLib.Tests.Zip.FastZipHandling.NonAsciiPasswords + ICSharpCode.SharpZipLib.Tests.Zip.FastZipHandling.UnicodeText + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.AddEntryAfterFinish + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.BasicDeflated + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.BasicDeflatedEncrypted + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.BasicDeflatedEncryptedNonSeekable + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.BasicDeflatedNonSeekable + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.BasicStored + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.BasicStoredEncrypted + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.BasicStoredEncryptedNonSeekable + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.BasicStoredNonSeekable + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.CloseOnlyHandled + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.ExerciseGetNextEntry + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.MixedEncryptedAndPlain + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.NameConversion + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.PartialStreamClosing + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.SerializedObject + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.SerializedObjectZeroLength + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.SetCommentOversize + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.SkipEncryptedEntriesWithoutSettingPassword + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.StoredNonSeekableConvertToDeflate + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.StoredNonSeekableKnownSizeNoCrc + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.StoredNonSeekableKnownSizeNoCrcEncrypted + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.Stream_UnicodeEntries + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.UnicodeNameConversion + ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.UnsupportedCompressionMethod + ICSharpCode.SharpZipLib.Tests.Zip.StreamHandling.BaseClosedAfterFailure + ICSharpCode.SharpZipLib.Tests.Zip.StreamHandling.BaseClosedWhenOwner + ICSharpCode.SharpZipLib.Tests.Zip.StreamHandling.BaseNotClosedWhenNotOwner + ICSharpCode.SharpZipLib.Tests.Zip.StreamHandling.CreateAndReadEmptyZip + ICSharpCode.SharpZipLib.Tests.Zip.StreamHandling.EmptyZipEntries + ICSharpCode.SharpZipLib.Tests.Zip.StreamHandling.EntryWithNoDataAndZip64 + ICSharpCode.SharpZipLib.Tests.Zip.StreamHandling.ParameterHandling + ICSharpCode.SharpZipLib.Tests.Zip.StreamHandling.ReadAndWriteZip64NonSeekable + ICSharpCode.SharpZipLib.Tests.Zip.StreamHandling.Zip64Descriptor + ICSharpCode.SharpZipLib.Tests.Zip.WindowsNameTransformHandling.LengthBoundaryOk + ICSharpCode.SharpZipLib.Tests.Zip.WindowsNameTransformHandling.NameTooLong + ICSharpCode.SharpZipLib.Tests.Zip.ZipEntryFactoryHandling.Defaults + ICSharpCode.SharpZipLib.Tests.Zip.ZipEntryHandling.CanDecompress + ICSharpCode.SharpZipLib.Tests.Zip.ZipEntryHandling.Cloning + ICSharpCode.SharpZipLib.Tests.Zip.ZipEntryHandling.Copying + ICSharpCode.SharpZipLib.Tests.Zip.ZipEntryHandling.NullEntryComment + ICSharpCode.SharpZipLib.Tests.Zip.ZipEntryHandling.NullNameInConstructor + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.BasicOperations + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.Deleting + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.ExceedSize + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.IsDataUnique + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.ReadOverrunInt + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.ReadOverrunLong + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.ReadOverrunShort + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.Skipping + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.TaggedDataHandling + ICSharpCode.SharpZipLib.Tests.Zip.ZipExtraDataHandling.UnreadCountValid + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.AddAndDeleteEntries + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.AddAndDeleteEntriesMemory + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.AddEncryptedEntriesToExistingArchive + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.AddToEmptyArchive + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.ArchiveTesting + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.BasicEncryption + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.BasicEncryptionToDisk + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.CreateEmptyArchive + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.Crypto_AddEncryptedEntryToExistingArchiveDirect + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.Crypto_AddEncryptedEntryToExistingArchiveSafe + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.EmbeddedArchive + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.FindEntriesInArchiveExtraData + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.FindEntriesInArchiveWithLongComment + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.FindEntry + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.HandlesNoEntries + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.NameFactory + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.NestedArchive + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.NullStreamDetected + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.RoundTrip + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.RoundTripInMemory + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.TestDirectoryEntry + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.TestEncryptedDirectoryEntry + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.UnicodeNames + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.UnreferencedZipFileClosingPartialStream + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.UpdateCommentOnlyInMemory + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.UpdateCommentOnlyOnDisk + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.Zip64Entries + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.Zip64Offset + ICSharpCode.SharpZipLib.Tests.Zip.ZipFileHandling.Zip64Useage + ICSharpCode.SharpZipLib.Tests.Zip.ZipNameTransformHandling.Basic + ICSharpCode.SharpZipLib.Tests.Zip.ZipNameTransformHandling.LengthBoundaryOk + ICSharpCode.SharpZipLib.Tests.Zip.ZipNameTransformHandling.NameTransforms + ICSharpCode.SharpZipLib.Tests.Zip.ZipNameTransformHandling.PathalogicalNames + ICSharpCode.SharpZipLib.Tests.Zip.ZipNameTransformHandling.TooLong + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/opencover-results-release.xml b/docs/opencover-results-release.xml new file mode 100644 index 000000000..691c4525f --- /dev/null +++ b/docs/opencover-results-release.xml @@ -0,0 +1,26247 @@ + + + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll + 2016-04-28T02:26:52.636468Z + mscorlib + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.1\tools\nunit3-console.exe + 2016-05-07T14:17:34.7070339Z + nunit3-console + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll + 2016-04-27T06:31:03.8601995Z + System + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.1\tools\nunit.engine.api.dll + 2016-05-07T14:17:34.660159Z + nunit.engine.api + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.1\tools\nunit.engine.dll + 2016-05-07T14:17:34.6914086Z + nunit.engine + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.1\tools\nunit.engine.dll + 2016-05-07T14:17:34.6914086Z + nunit.engine + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll + 2016-01-23T02:45:41.3556585Z + System.Xml + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll + 2016-02-24T01:49:04.6045612Z + System.Web + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.1\tools\Mono.Cecil.dll + 2016-05-07T14:17:34.5064714Z + Mono.Cecil + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Remoting\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.Remoting.dll + 2015-10-30T07:19:38.0026412Z + System.Runtime.Remoting + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll + 2015-10-30T07:19:36.3463962Z + System.Configuration + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll + 2016-04-28T02:26:52.636468Z + mscorlib + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.1\tools\nunit-agent.exe + 2016-05-07T14:17:34.6122731Z + nunit-agent + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.1\tools\nunit.engine.dll + 2016-05-07T14:17:34.6914086Z + nunit.engine + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.1\tools\nunit.engine.api.dll + 2016-05-07T14:17:34.660159Z + nunit.engine.api + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll + 2016-04-27T06:31:03.8601995Z + System + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Remoting\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.Remoting.dll + 2015-10-30T07:19:38.0026412Z + System.Runtime.Remoting + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll + 2016-01-23T02:45:41.3556585Z + System.Xml + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll + 2016-02-24T01:49:04.6045612Z + System.Web + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.1\tools\Mono.Cecil.dll + 2016-05-07T14:17:34.5064714Z + Mono.Cecil + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll + 2015-10-30T07:19:36.3463962Z + System.Configuration + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\bin\Release\nunit.framework.dll + 2016-05-07T14:17:32.4666905Z + nunit.framework + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll + 2016-04-27T06:31:03.8601995Z + System + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll + 2016-02-24T01:49:04.6045612Z + System.Web + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\bin\Release\ICSharpCode.SharpZipLib.Tests.dll + 2016-05-17T23:07:50.1388844Z + ICSharpCode.SharpZipLib.Tests + + + + + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\bin\Release\ICSharpCode.SharpZipLib.dll + 2016-05-17T23:07:43.011793Z + ICSharpCode.SharpZipLib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <Module> + + + + + ICSharpCode.SharpZipLib.SharpZipBaseException + + + + 100663297 + System.Void ICSharpCode.SharpZipLib.SharpZipBaseException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) + + + + + + + + + + + 100663298 + System.Void ICSharpCode.SharpZipLib.SharpZipBaseException::.ctor() + + + + + + + + + + + 100663299 + System.Void ICSharpCode.SharpZipLib.SharpZipBaseException::.ctor(System.String) + + + + + + + + + + + 100663300 + System.Void ICSharpCode.SharpZipLib.SharpZipBaseException::.ctor(System.String,System.Exception) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.FastZipEvents + + + + 100663308 + System.TimeSpan ICSharpCode.SharpZipLib.Zip.FastZipEvents::get_ProgressInterval() + + + + + + + + + + 100663309 + System.Void ICSharpCode.SharpZipLib.Zip.FastZipEvents::set_ProgressInterval(System.TimeSpan) + + + + + + + + + + + 100663301 + System.Void ICSharpCode.SharpZipLib.Zip.FastZipEvents::add_ProcessDirectory(System.EventHandler`1<ICSharpCode.SharpZipLib.Core.DirectoryEventArgs>) + + + + + + + 100663302 + System.Void ICSharpCode.SharpZipLib.Zip.FastZipEvents::remove_ProcessDirectory(System.EventHandler`1<ICSharpCode.SharpZipLib.Core.DirectoryEventArgs>) + + + + + + + 100663303 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnDirectoryFailure(System.String,System.Exception) + + + + + + + + + + + + + + + + + + + 100663304 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnFileFailure(System.String,System.Exception) + + + + + + + + + + + + + + + + + + + 100663305 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnProcessFile(System.String) + + + + + + + + + + + + + + + + + + + 100663306 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnCompletedFile(System.String) + + + + + + + + + + + + + + + + + + + 100663307 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnProcessDirectory(System.String,System.Boolean) + + + + + + + + + + + + + + + + + + + 100663310 + System.Void ICSharpCode.SharpZipLib.Zip.FastZipEvents::.ctor() + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.FastZip + + + + 100663313 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip::get_CreateEmptyDirectories() + + + + + + + + + + 100663314 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_CreateEmptyDirectories(System.Boolean) + + + + + + + + + + + 100663315 + System.String ICSharpCode.SharpZipLib.Zip.FastZip::get_Password() + + + + + + + + + + 100663316 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_Password(System.String) + + + + + + + + + + + 100663317 + ICSharpCode.SharpZipLib.Core.INameTransform ICSharpCode.SharpZipLib.Zip.FastZip::get_NameTransform() + + + + + + + + + + 100663318 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_NameTransform(ICSharpCode.SharpZipLib.Core.INameTransform) + + + + + + + + + + + 100663319 + ICSharpCode.SharpZipLib.Zip.IEntryFactory ICSharpCode.SharpZipLib.Zip.FastZip::get_EntryFactory() + + + + + + + + + + 100663320 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_EntryFactory(ICSharpCode.SharpZipLib.Zip.IEntryFactory) + + + + + + + + + + + + + + + + + 100663321 + ICSharpCode.SharpZipLib.Zip.UseZip64 ICSharpCode.SharpZipLib.Zip.FastZip::get_UseZip64() + + + + + + + + + + 100663322 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_UseZip64(ICSharpCode.SharpZipLib.Zip.UseZip64) + + + + + + + + + + + 100663323 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip::get_RestoreDateTimeOnExtract() + + + + + + + + + + 100663324 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_RestoreDateTimeOnExtract(System.Boolean) + + + + + + + + + + + 100663325 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip::get_RestoreAttributesOnExtract() + + + + + + + + + + 100663326 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_RestoreAttributesOnExtract(System.Boolean) + + + + + + + + + + + 100663311 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::.ctor() + + + + + + + + + + + + + 100663312 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::.ctor(ICSharpCode.SharpZipLib.Zip.FastZipEvents) + + + + + + + + + + + + + + 100663327 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::CreateZip(System.String,System.String,System.Boolean,System.String,System.String) + + + + + + + + + + + 100663328 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::CreateZip(System.String,System.String,System.Boolean,System.String) + + + + + + + + + + + 100663329 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::CreateZip(System.IO.Stream,System.String,System.Boolean,System.String,System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663330 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ExtractZip(System.String,System.String,System.String) + + + + + + + + + + + 100663331 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ExtractZip(System.String,System.String,ICSharpCode.SharpZipLib.Zip.FastZip/Overwrite,ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate,System.String,System.String,System.Boolean) + + + + + + + + + + + + 100663332 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ExtractZip(System.IO.Stream,System.String,ICSharpCode.SharpZipLib.Zip.FastZip/Overwrite,ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate,System.String,System.String,System.Boolean,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663333 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ProcessDirectory(System.Object,ICSharpCode.SharpZipLib.Core.DirectoryEventArgs) + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663334 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ProcessFile(System.Object,ICSharpCode.SharpZipLib.Core.ScanEventArgs) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663335 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::AddFileContents(System.String,System.IO.Stream) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663336 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ExtractFileEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry,System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663337 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ExtractEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663338 + System.Int32 ICSharpCode.SharpZipLib.Zip.FastZip::MakeExternalAttributes(System.IO.FileInfo) + + + + + + + + + + 100663339 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip::NameIsValid(System.String) + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate + + + 100664489 + System.Void ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate::.ctor(System.Object,System.IntPtr) + + + + + 100664490 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate::Invoke(System.String) + + + + + 100664491 + System.IAsyncResult ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate::BeginInvoke(System.String,System.AsyncCallback,System.Object) + + + + + 100664492 + System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Zip.WindowsNameTransform + + + + 100663349 + System.String ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::get_BaseDirectory() + + + + + + + + + + 100663350 + System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::set_BaseDirectory(System.String) + + + + + + + + + + + + + + + + 100663351 + System.Boolean ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::get_TrimIncomingPaths() + + + + + + + + + + 100663352 + System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::set_TrimIncomingPaths(System.Boolean) + + + + + + + + + + + 100663358 + System.Char ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::get_Replacement() + + + + + + + + + + 100663359 + System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::set_Replacement(System.Char) + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663347 + System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::.ctor(System.String) + + + + + + + + + + + + + + + + + + 100663348 + System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::.ctor() + + + + + + + + + + + + 100663353 + System.String ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::TransformDirectory(System.String) + + + + + + + + + + + + + + + + + + + + + 100663354 + System.String ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::TransformFile(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + 100663355 + System.Boolean ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::IsValidName(System.String) + + + + + + + + + + + 100663356 + System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::.cctor() + + + + + + + + + + + + + + + + + 100663357 + System.String ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::MakeValidName(System.String,System.Char) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipConstants + + + + 100663360 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipConstants::get_DefaultCodePage() + + + + + + + + + + 100663361 + System.Void ICSharpCode.SharpZipLib.Zip.ZipConstants::set_DefaultCodePage(System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + 100663362 + System.String ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToString(System.Byte[],System.Int32) + + + + + + + + + + + + + + + 100663363 + System.String ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToString(System.Byte[]) + + + + + + + + + + + + + + + 100663364 + System.String ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToStringExt(System.Int32,System.Byte[],System.Int32) + + + + + + + + + + + + + + + + + + + 100663365 + System.String ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToStringExt(System.Int32,System.Byte[]) + + + + + + + + + + + + + + + + + + + 100663366 + System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToArray(System.String) + + + + + + + + + + + + + + + 100663367 + System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToArray(System.Int32,System.String) + + + + + + + + + + + + + + + + + + + 100663368 + System.Void ICSharpCode.SharpZipLib.Zip.ZipConstants::.ctor() + + + + + + + + + + + 100663369 + System.Void ICSharpCode.SharpZipLib.Zip.ZipConstants::.cctor() + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipEntry + + + + 100663374 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_HasCrc() + + + + + + + + + + 100663375 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsCrypted() + + + + + + + + + + 100663376 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_IsCrypted(System.Boolean) + + + + + + + + + + + + + + + + + 100663377 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsUnicodeText() + + + + + + + + + + 100663378 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_IsUnicodeText(System.Boolean) + + + + + + + + + + + + + + + + + 100663379 + System.Byte ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CryptoCheckValue() + + + + + + + + + + 100663380 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_CryptoCheckValue(System.Byte) + + + + + + + + + + + 100663381 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Flags() + + + + + + + + + + 100663382 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Flags(System.Int32) + + + + + + + + + + + 100663383 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_ZipFileIndex() + + + + + + + + + + 100663384 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_ZipFileIndex(System.Int64) + + + + + + + + + + + 100663385 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Offset() + + + + + + + + + + 100663386 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Offset(System.Int64) + + + + + + + + + + + 100663387 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_ExternalFileAttributes() + + + + + + + + + + + + + + + 100663388 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_ExternalFileAttributes(System.Int32) + + + + + + + + + + + + 100663389 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_VersionMadeBy() + + + + + + + + + + 100663390 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsDOSEntry() + + + + + + + + + + 100663392 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_HostSystem() + + + + + + + + + + 100663393 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_HostSystem(System.Int32) + + + + + + + + + + + + 100663394 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Version() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663395 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CanDecompress() + + + + + + + + + + + + + 100663398 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_LocalHeaderRequiresZip64() + + + + + + + + + + + + + + + + + + + + + + + 100663399 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CentralHeaderRequiresZip64() + + + + + + + + + + 100663400 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_DosTime() + + + + + + + + + + + + + + + 100663401 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_DosTime(System.Int64) + + + + + + + + + + + + 100663402 + System.DateTime ICSharpCode.SharpZipLib.Zip.ZipEntry::get_DateTime() + + + + + + + + + + 100663403 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_DateTime(System.DateTime) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663404 + System.String ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Name() + + + + + + + + + + 100663405 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Size() + + + + + + + + + + + + + 100663406 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Size(System.Int64) + + + + + + + + + + + + 100663407 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CompressedSize() + + + + + + + + + + + + + 100663408 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_CompressedSize(System.Int64) + + + + + + + + + + + + 100663409 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Crc() + + + + + + + + + + + + + 100663410 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Crc(System.Int64) + + + + + + + + + + + + + + + + + 100663411 + ICSharpCode.SharpZipLib.Zip.CompressionMethod ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CompressionMethod() + + + + + + + + + + 100663412 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_CompressionMethod(ICSharpCode.SharpZipLib.Zip.CompressionMethod) + + + + + + + + + + + + + + + + 100663413 + ICSharpCode.SharpZipLib.Zip.CompressionMethod ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CompressionMethodForHeader() + + + + + + + + + + + + + 100663414 + System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipEntry::get_ExtraData() + + + + + + + + + + 100663415 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_ExtraData(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + 100663416 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_AESKeySize() + + + + + + + + + + + + + + + + + + + + + 100663417 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_AESKeySize(System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + 100663418 + System.Byte ICSharpCode.SharpZipLib.Zip.ZipEntry::get_AESEncryptionStrength() + + + + + + + + + + 100663419 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_AESSaltLen() + + + + + + + + + + 100663420 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_AESOverheadSize() + + + + + + + + + + 100663424 + System.String ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Comment() + + + + + + + + + + 100663425 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Comment(System.String) + + + + + + + + + + + + + + + + + + 100663426 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsDirectory() + + + + + + + + + + + + 100663427 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsFile() + + + + + + + + + + 100663370 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::.ctor(System.String) + + + + + + + + + + + 100663371 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::.ctor(System.String,System.Int32) + + + + + + + + + + + 100663372 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::.ctor(System.String,System.Int32,System.Int32,ICSharpCode.SharpZipLib.Zip.CompressionMethod) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663373 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::.ctor(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663391 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::HasDosAttributes(System.Int32) + + + + + + + + + + + + + + + + 100663396 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::ForceZip64() + + + + + + + + + + + 100663397 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::IsZip64Forced() + + + + + + + + + + 100663421 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::ProcessExtraData(System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663422 + System.DateTime ICSharpCode.SharpZipLib.Zip.ZipEntry::GetDateTime(ICSharpCode.SharpZipLib.Zip.ZipExtraData) + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663423 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::ProcessAESExtraData(ICSharpCode.SharpZipLib.Zip.ZipExtraData) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663428 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::IsCompressionMethodSupported() + + + + + + + + + + 100663429 + System.Object ICSharpCode.SharpZipLib.Zip.ZipEntry::Clone() + + + + + + + + + + + + + + + + + 100663430 + System.String ICSharpCode.SharpZipLib.Zip.ZipEntry::ToString() + + + + + + + + + + 100663431 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::IsCompressionMethodSupported(ICSharpCode.SharpZipLib.Zip.CompressionMethod) + + + + + + + + + + 100663432 + System.String ICSharpCode.SharpZipLib.Zip.ZipEntry::CleanName(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipEntryFactory + + + + 100663436 + ICSharpCode.SharpZipLib.Core.INameTransform ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_NameTransform() + + + + + + + + + + 100663437 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_NameTransform(ICSharpCode.SharpZipLib.Core.INameTransform) + + + + + + + + + + + + + + + + + 100663438 + ICSharpCode.SharpZipLib.Zip.ZipEntryFactory/TimeSetting ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_Setting() + + + + + + + + + + 100663439 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_Setting(ICSharpCode.SharpZipLib.Zip.ZipEntryFactory/TimeSetting) + + + + + + + + + + + 100663440 + System.DateTime ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_FixedDateTime() + + + + + + + + + + 100663441 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_FixedDateTime(System.DateTime) + + + + + + + + + + + + + + + + 100663442 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_GetAttributes() + + + + + + + + + + 100663443 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_GetAttributes(System.Int32) + + + + + + + + + + + 100663444 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_SetAttributes() + + + + + + + + + + 100663445 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_SetAttributes(System.Int32) + + + + + + + + + + + 100663446 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_IsUnicodeText() + + + + + + + + + + 100663447 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_IsUnicodeText(System.Boolean) + + + + + + + + + + + 100663433 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::.ctor() + + + + + + + + + + + + + + 100663434 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::.ctor(ICSharpCode.SharpZipLib.Zip.ZipEntryFactory/TimeSetting) + + + + + + + + + + + + + + + 100663435 + System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::.ctor(System.DateTime) + + + + + + + + + + + + + + + + 100663448 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeFileEntry(System.String) + + + + + + + + + + 100663449 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeFileEntry(System.String,System.Boolean) + + + + + + + + + + 100663450 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeFileEntry(System.String,System.String,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663451 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeDirectoryEntry(System.String) + + + + + + + + + + 100663452 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeDirectoryEntry(System.String,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipException + + + + 100663453 + System.Void ICSharpCode.SharpZipLib.Zip.ZipException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) + + + + + + + + + + + 100663454 + System.Void ICSharpCode.SharpZipLib.Zip.ZipException::.ctor() + + + + + + + + + + + 100663455 + System.Void ICSharpCode.SharpZipLib.Zip.ZipException::.ctor(System.String) + + + + + + + + + + + 100663456 + System.Void ICSharpCode.SharpZipLib.Zip.ZipException::.ctor(System.String,System.Exception) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.RawTaggedData + + + + 100663461 + System.Int16 ICSharpCode.SharpZipLib.Zip.RawTaggedData::get_TagID() + + + + + + + + + + 100663462 + System.Void ICSharpCode.SharpZipLib.Zip.RawTaggedData::set_TagID(System.Int16) + + + + + + + + + + + 100663465 + System.Byte[] ICSharpCode.SharpZipLib.Zip.RawTaggedData::get_Data() + + + + + + + + + + 100663466 + System.Void ICSharpCode.SharpZipLib.Zip.RawTaggedData::set_Data(System.Byte[]) + + + + + + + + + + + 100663460 + System.Void ICSharpCode.SharpZipLib.Zip.RawTaggedData::.ctor(System.Int16) + + + + + + + + + + + + 100663463 + System.Void ICSharpCode.SharpZipLib.Zip.RawTaggedData::SetData(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + 100663464 + System.Byte[] ICSharpCode.SharpZipLib.Zip.RawTaggedData::GetData() + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ExtendedUnixData + + + + 100663467 + System.Int16 ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_TagID() + + + + + + + + + + 100663471 + System.DateTime ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_ModificationTime() + + + + + + + + + + 100663472 + System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::set_ModificationTime(System.DateTime) + + + + + + + + + + + + + + + + + 100663473 + System.DateTime ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_AccessTime() + + + + + + + + + + 100663474 + System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::set_AccessTime(System.DateTime) + + + + + + + + + + + + + + + + + 100663475 + System.DateTime ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_CreateTime() + + + + + + + + + + 100663476 + System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::set_CreateTime(System.DateTime) + + + + + + + + + + + + + + + + + 100663477 + ICSharpCode.SharpZipLib.Zip.ExtendedUnixData/Flags ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_Include() + + + + + + + + + + 100663478 + System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::set_Include(ICSharpCode.SharpZipLib.Zip.ExtendedUnixData/Flags) + + + + + + + + + + + 100663468 + System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::SetData(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663469 + System.Byte[] ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::GetData() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663470 + System.Boolean ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::IsValidValue(System.DateTime) + + + + + + + + + + 100663479 + System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::.ctor() + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.NTTaggedData + + + + 100663480 + System.Int16 ICSharpCode.SharpZipLib.Zip.NTTaggedData::get_TagID() + + + + + + + + + + 100663484 + System.DateTime ICSharpCode.SharpZipLib.Zip.NTTaggedData::get_LastModificationTime() + + + + + + + + + + 100663485 + System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::set_LastModificationTime(System.DateTime) + + + + + + + + + + + + + + + + 100663486 + System.DateTime ICSharpCode.SharpZipLib.Zip.NTTaggedData::get_CreateTime() + + + + + + + + + + 100663487 + System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::set_CreateTime(System.DateTime) + + + + + + + + + + + + + + + + 100663488 + System.DateTime ICSharpCode.SharpZipLib.Zip.NTTaggedData::get_LastAccessTime() + + + + + + + + + + 100663489 + System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::set_LastAccessTime(System.DateTime) + + + + + + + + + + + + + + + + 100663481 + System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::SetData(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663482 + System.Byte[] ICSharpCode.SharpZipLib.Zip.NTTaggedData::GetData() + + + + + + + + + + + + + + + + + + + + 100663483 + System.Boolean ICSharpCode.SharpZipLib.Zip.NTTaggedData::IsValidValue(System.DateTime) + + + + + + + + + + + + + + + + 100663490 + System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::.ctor() + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipExtraData + + + + 100663496 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::get_Length() + + + + + + + + + + 100663499 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::get_ValueLength() + + + + + + + + + + 100663500 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::get_CurrentReadIndex() + + + + + + + + + + 100663501 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::get_UnreadCount() + + + + + + + + + + + + + + + + + 100663492 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::.ctor() + + + + + + + + + + + + 100663493 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::.ctor(System.Byte[]) + + + + + + + + + + + + + + + + + + 100663494 + System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipExtraData::GetEntryData() + + + + + + + + + + + + + + + 100663495 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::Clear() + + + + + + + + + + + + + + + + + 100663497 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipExtraData::GetStreamForTag(System.Int32) + + + + + + + + + + + + + + + + 100663498 + T ICSharpCode.SharpZipLib.Zip.ZipExtraData::GetData() + + + + + + + + + + + + + + + + + 100663502 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipExtraData::Find(System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663503 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddEntry(ICSharpCode.SharpZipLib.Zip.ITaggedData) + + + + + + + + + + + + + + + + 100663504 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddEntry(System.Int32,System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663505 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::StartNewEntry() + + + + + + + + + + + 100663506 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddNewEntry(System.Int32) + + + + + + + + + + + + + 100663507 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddData(System.Byte) + + + + + + + + + + + 100663508 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddData(System.Byte[]) + + + + + + + + + + + + + + + + 100663509 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddLeShort(System.Int32) + + + + + + + + + + + + 100663510 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddLeInt(System.Int32) + + + + + + + + + + + + 100663511 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddLeLong(System.Int64) + + + + + + + + + + + + 100663512 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipExtraData::Delete(System.Int32) + + + + + + + + + + + + + + + + + + + + + + 100663513 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadLong() + + + + + + + + + + + 100663514 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadInt() + + + + + + + + + + + + + 100663515 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadShort() + + + + + + + + + + + + + 100663516 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadByte() + + + + + + + + + + + + + + + + + + + 100663517 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::Skip(System.Int32) + + + + + + + + + + + + 100663518 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadCheck(System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + 100663519 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadShortInternal() + + + + + + + + + + + + + + + + + 100663520 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::SetShort(System.Int32&,System.Int32) + + + + + + + + + + + + + 100663521 + System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::Dispose() + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs + + + + 100663524 + System.String ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::get_FileName() + + + + + + + + + + 100663525 + System.Byte[] ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::get_Key() + + + + + + + + + + 100663526 + System.Void ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::set_Key(System.Byte[]) + + + + + + + + + + + 100663522 + System.Void ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::.ctor(System.String) + + + + + + + + + + + + 100663523 + System.Void ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::.ctor(System.String,System.Byte[]) + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.TestStatus + + + + 100663528 + ICSharpCode.SharpZipLib.Zip.TestOperation ICSharpCode.SharpZipLib.Zip.TestStatus::get_Operation() + + + + + + + + + + 100663529 + ICSharpCode.SharpZipLib.Zip.ZipFile ICSharpCode.SharpZipLib.Zip.TestStatus::get_File() + + + + + + + + + + 100663530 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.TestStatus::get_Entry() + + + + + + + + + + 100663531 + System.Int32 ICSharpCode.SharpZipLib.Zip.TestStatus::get_ErrorCount() + + + + + + + + + + 100663532 + System.Int64 ICSharpCode.SharpZipLib.Zip.TestStatus::get_BytesTested() + + + + + + + + + + 100663533 + System.Boolean ICSharpCode.SharpZipLib.Zip.TestStatus::get_EntryValid() + + + + + + + + + + 100663527 + System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile) + + + + + + + + + + + + 100663534 + System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::AddError() + + + + + + + + + + + + 100663535 + System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::SetOperation(ICSharpCode.SharpZipLib.Zip.TestOperation) + + + + + + + + + + + 100663536 + System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::SetEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + 100663537 + System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::SetBytesTested(System.Int64) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler + + + 100663538 + System.Void ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler::.ctor(System.Object,System.IntPtr) + + + + + 100663539 + System.Void ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler::Invoke(ICSharpCode.SharpZipLib.Zip.TestStatus,System.String) + + + + + 100663540 + System.IAsyncResult ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler::BeginInvoke(ICSharpCode.SharpZipLib.Zip.TestStatus,System.String,System.AsyncCallback,System.Object) + + + + + 100663541 + System.Void ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipFile + + + + 100663543 + System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipFile::get_Key() + + + + + + + + + + 100663544 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_Key(System.Byte[]) + + + + + + + + + + + 100663545 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_Password(System.String) + + + + + + + + + + + + + + + + + + 100663546 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_HaveKeys() + + + + + + + + + + 100663555 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_IsStreamOwner() + + + + + + + + + + 100663556 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100663557 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_IsEmbeddedArchive() + + + + + + + + + + 100663558 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_IsNewArchive() + + + + + + + + + + 100663559 + System.String ICSharpCode.SharpZipLib.Zip.ZipFile::get_ZipFileComment() + + + + + + + + + + 100663560 + System.String ICSharpCode.SharpZipLib.Zip.ZipFile::get_Name() + + + + + + + + + + 100663561 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::get_Size() + + + + + + + + + + 100663562 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile::get_Count() + + + + + + + + + + 100663563 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipFile::get_EntryByIndex(System.Int32) + + + + + + + + + + 100663572 + ICSharpCode.SharpZipLib.Core.INameTransform ICSharpCode.SharpZipLib.Zip.ZipFile::get_NameTransform() + + + + + + + + + + 100663573 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_NameTransform(ICSharpCode.SharpZipLib.Core.INameTransform) + + + + + + + + + + + 100663574 + ICSharpCode.SharpZipLib.Zip.IEntryFactory ICSharpCode.SharpZipLib.Zip.ZipFile::get_EntryFactory() + + + + + + + + + + 100663575 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_EntryFactory(ICSharpCode.SharpZipLib.Zip.IEntryFactory) + + + + + + + + + + + + + + + + + 100663576 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::get_BufferSize() + + + + + + + + + + 100663577 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_BufferSize(System.Int32) + + + + + + + + + + + + + + + + + + + + 100663578 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_IsUpdating() + + + + + + + + + + 100663579 + ICSharpCode.SharpZipLib.Zip.UseZip64 ICSharpCode.SharpZipLib.Zip.ZipFile::get_UseZip64() + + + + + + + + + + 100663580 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_UseZip64(ICSharpCode.SharpZipLib.Zip.UseZip64) + + + + + + + + + + + 100663542 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::OnKeysRequired(System.String) + + + + + + + + + + + + + + + + + 100663547 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::.ctor(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663548 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::.ctor(System.IO.FileStream) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663549 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::.ctor(System.IO.Stream) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663550 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::.ctor() + + + + + + + + + + + + + + + + 100663551 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Finalize() + + + + + + + + + + + + 100663552 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Close() + + + + + + + + + + + + 100663553 + ICSharpCode.SharpZipLib.Zip.ZipFile ICSharpCode.SharpZipLib.Zip.ZipFile::Create(System.String) + + + + + + + + + + + + + + + + + + + + 100663554 + ICSharpCode.SharpZipLib.Zip.ZipFile ICSharpCode.SharpZipLib.Zip.ZipFile::Create(System.IO.Stream) + + + + + + + + + + + + + + + + + + + + + + + + + 100663564 + System.Collections.IEnumerator ICSharpCode.SharpZipLib.Zip.ZipFile::GetEnumerator() + + + + + + + + + + + + + + + 100663565 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::FindEntry(System.String,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + 100663566 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipFile::GetEntry(System.String) + + + + + + + + + + + + + + + + + + 100663567 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::GetInputStream(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663568 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::GetInputStream(System.Int64) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663569 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::TestArchive(System.Boolean) + + + + + + + + + + 100663570 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::TestArchive(System.Boolean,ICSharpCode.SharpZipLib.Zip.TestStrategy,ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663571 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile::TestLocalHeader(ICSharpCode.SharpZipLib.Zip.ZipEntry,ICSharpCode.SharpZipLib.Zip.ZipFile/HeaderTest) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663581 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::BeginUpdate(ICSharpCode.SharpZipLib.Zip.IArchiveStorage,ICSharpCode.SharpZipLib.Zip.IDynamicDataSource) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663582 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::BeginUpdate(ICSharpCode.SharpZipLib.Zip.IArchiveStorage) + + + + + + + + + + + 100663583 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::BeginUpdate() + + + + + + + + + + + + + + + + + 100663584 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CommitUpdate() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663585 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::AbortUpdate() + + + + + + + + + + + 100663586 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::SetComment(System.String) + + + + + + + + + + + + + + + + + + + + + + + 100663587 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::AddUpdate(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) + + + + + + + + + + + + + + + + + + + + + + + + + 100663588 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663589 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod) + + + + + + + + + + + + + + + + + + + + + + + + 100663590 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(System.String) + + + + + + + + + + + + + + + + + 100663591 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(System.String,System.String) + + + + + + + + + + + + + + + + + + + + + 100663592 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,System.String) + + + + + + + + + + + + + + + + + + + + + 100663593 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod) + + + + + + + + + + + + + + + + + + + + + + + 100663594 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + 100663595 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + 100663596 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::AddDirectory(System.String) + + + + + + + + + + + + + + + + + + 100663597 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::Delete(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663598 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Delete(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + 100663599 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEShort(System.Int32) + + + + + + + + + + + + 100663600 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEUshort(System.UInt16) + + + + + + + + + + + + 100663601 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEInt(System.Int32) + + + + + + + + + + + + 100663602 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEUint(System.UInt32) + + + + + + + + + + + + 100663603 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLeLong(System.Int64) + + + + + + + + + + + + 100663604 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEUlong(System.UInt64) + + + + + + + + + + + + 100663605 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLocalEntryHeader(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663606 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::WriteCentralDirectoryHeader(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663607 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::PostUpdateCleanup() + + + + + + + + + + + + + + + + + + + 100663608 + System.String ICSharpCode.SharpZipLib.Zip.ZipFile::GetTransformedFileName(System.String) + + + + + + + + + + + + + + 100663609 + System.String ICSharpCode.SharpZipLib.Zip.ZipFile::GetTransformedDirectoryName(System.String) + + + + + + + + + + + + + + 100663610 + System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipFile::GetBuffer() + + + + + + + + + + + + + + + 100663611 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyDescriptorBytes(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.IO.Stream,System.IO.Stream) + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663612 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyBytes(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.IO.Stream,System.IO.Stream,System.Int64,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663613 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::GetDescriptorSize(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) + + + + + + + + + + + + + + + + + + + + 100663614 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyDescriptorBytesDirect(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.IO.Stream,System.Int64&,System.Int64) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663615 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyEntryDataDirect(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.IO.Stream,System.Boolean,System.Int64&,System.Int64&) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663616 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::FindExistingUpdate(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + 100663617 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::FindExistingUpdate(System.String) + + + + + + + + + + + + + + + + + 100663618 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::GetOutputStream(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663619 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::AddEntry(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663620 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::ModifyEntry(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) + + + + + + + + + + + + + + + + + + + + + + + + 100663621 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyEntryDirect(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.Int64&) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663622 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyEntry(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) + + + + + + + + + + + + + + + + + + + + + + 100663623 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Reopen(System.IO.Stream) + + + + + + + + + + + + + + + + + + 100663624 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Reopen() + + + + + + + + + + + + + + + + 100663625 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::UpdateCommentOnly() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663626 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::RunUpdates() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663627 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CheckUpdating() + + + + + + + + + + + + + + + 100663628 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::System.IDisposable.Dispose() + + + + + + + + + + + 100663629 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::DisposeInternal(System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + 100663630 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Dispose(System.Boolean) + + + + + + + + + + + 100663631 + System.UInt16 ICSharpCode.SharpZipLib.Zip.ZipFile::ReadLEUshort() + + + + + + + + + + + + + + + + + + + + + 100663632 + System.UInt32 ICSharpCode.SharpZipLib.Zip.ZipFile::ReadLEUint() + + + + + + + + + + 100663633 + System.UInt64 ICSharpCode.SharpZipLib.Zip.ZipFile::ReadLEUlong() + + + + + + + + + + 100663634 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile::LocateBlockWithSignature(System.Int32,System.Int64,System.Int32,System.Int32) + + + + + + + + + + + + 100663635 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::ReadEntries() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663636 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile::LocateEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + 100663637 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::CreateAndInitDecryptionStream(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663638 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::CreateAndInitEncryptionStream(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663639 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CheckClassicPassword(System.Security.Cryptography.CryptoStream,ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + 100663640 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteEncryptionHeader(System.IO.Stream,System.Int64) + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler + + + 100664493 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler::.ctor(System.Object,System.IntPtr) + + + + + 100664494 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs) + + + + + 100664495 + System.IAsyncResult ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs,System.AsyncCallback,System.Object) + + + + + 100664496 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipFile/UpdateComparer + + + + 100664497 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/UpdateComparer::Compare(System.Object,System.Object) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664498 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UpdateComparer::.ctor() + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate + + + + 100664507 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_Entry() + + + + + + + + + + 100664508 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_OutEntry() + + + + + + + + + + + + + + + 100664509 + ICSharpCode.SharpZipLib.Zip.ZipFile/UpdateCommand ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_Command() + + + + + + + + + + 100664510 + System.String ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_Filename() + + + + + + + + + + 100664511 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_SizePatchOffset() + + + + + + + + + + 100664512 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::set_SizePatchOffset(System.Int64) + + + + + + + + + + + 100664513 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_CrcPatchOffset() + + + + + + + + + + 100664514 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::set_CrcPatchOffset(System.Int64) + + + + + + + + + + + 100664515 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_OffsetBasedSize() + + + + + + + + + + 100664516 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::set_OffsetBasedSize(System.Int64) + + + + + + + + + + + 100664499 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(System.String,ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + 100664500 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(System.String,System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod) + + + + + + + + + + + + + + + + + + 100664501 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(System.String,System.String) + + + + + + + + + + + 100664502 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod) + + + + + + + + + + + + + + + + + + 100664503 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + 100664504 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.ZipEntry,ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + 100664505 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile/UpdateCommand,ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + 100664506 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + 100664517 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::GetSource() + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString + + + + 100664520 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::get_IsSourceString() + + + + + + + + + + 100664521 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::get_RawLength() + + + + + + + + + + + 100664522 + System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::get_RawComment() + + + + + + + + + + + 100664518 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::.ctor(System.String) + + + + + + + + + + + + + 100664519 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::.ctor(System.Byte[]) + + + + + + + + + + + + 100664523 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::Reset() + + + + + + + + + + + + + + + + + 100664524 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::MakeTextAvailable() + + + + + + + + + + + + + + + 100664525 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::MakeBytesAvailable() + + + + + + + + + + + + + + + 100664526 + System.String ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::op_Implicit(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipFile/ZipEntryEnumerator + + + + 100664528 + System.Object ICSharpCode.SharpZipLib.Zip.ZipFile/ZipEntryEnumerator::get_Current() + + + + + + + + + + 100664527 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipEntryEnumerator::.ctor(ICSharpCode.SharpZipLib.Zip.ZipEntry[]) + + + + + + + + + + + + + 100664529 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipEntryEnumerator::Reset() + + + + + + + + + + + 100664530 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/ZipEntryEnumerator::MoveNext() + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream + + + + 100664533 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_CanRead() + + + + + + + + + + 100664535 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_CanWrite() + + + + + + + + + + 100664536 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_CanSeek() + + + + + + + + + + 100664537 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_Length() + + + + + + + + + + 100664538 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_Position() + + + + + + + + + + 100664539 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::set_Position(System.Int64) + + + + + + + + + + 100664531 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::.ctor(System.IO.Stream) + + + + + + + + + + + + 100664532 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Close() + + + + + + + + + + 100664534 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Flush() + + + + + + + + + + + 100664540 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100664541 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + 100664542 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::SetLength(System.Int64) + + + + + + + + + + 100664543 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream + + + + 100664552 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_Position() + + + + + + + + + + 100664553 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::set_Position(System.Int64) + + + + + + + + + + + + + + + + + + + + + 100664554 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_Length() + + + + + + + + + + 100664555 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_CanWrite() + + + + + + + + + + 100664556 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_CanSeek() + + + + + + + + + + 100664557 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_CanRead() + + + + + + + + + + 100664558 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_CanTimeout() + + + + + + + + + + 100664544 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile,System.Int64,System.Int64) + + + + + + + + + + + + + + + + + 100664545 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::ReadByte() + + + + + + + + + + + + + + + + + + 100664546 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Close() + + + + + + + + + + 100664547 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664548 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100664549 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::SetLength(System.Int64) + + + + + + + + + + 100664550 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664551 + System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Flush() + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource + + + + 100663643 + System.Void ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource::.ctor(System.String) + + + + + + + + + + + + 100663644 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource::GetSource() + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource + + + + 100663645 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource::GetSource(ICSharpCode.SharpZipLib.Zip.ZipEntry,System.String) + + + + + + + + + + + + + + + + 100663646 + System.Void ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource::.ctor() + + + + + + + + + ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage + + + + 100663659 + ICSharpCode.SharpZipLib.Zip.FileUpdateMode ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage::get_UpdateMode() + + + + + + + + + + 100663653 + System.Void ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage::.ctor(ICSharpCode.SharpZipLib.Zip.FileUpdateMode) + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage + + + + 100663660 + System.Void ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.FileUpdateMode) + + + + + + + + + + + + + + + + + 100663661 + System.Void ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile) + + + + + + + + + + + 100663662 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::GetTemporaryOutput() + + + + + + + + + + + + + + + + + + + 100663663 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::ConvertTemporaryToFinal() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663664 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::MakeTemporaryCopy(System.IO.Stream) + + + + + + + + + + + + + + 100663665 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::OpenForDirectUpdate(System.IO.Stream) + + + + + + + + + + + + + + + + + + + + + + + 100663666 + System.Void ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::Dispose() + + + + + + + + + + + + + + + 100663667 + System.String ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::GetTempFileName(System.String,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage + + + + 100663670 + System.IO.MemoryStream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::get_FinalStream() + + + + + + + + + + 100663668 + System.Void ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::.ctor() + + + + + + + + + + + 100663669 + System.Void ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::.ctor(ICSharpCode.SharpZipLib.Zip.FileUpdateMode) + + + + + + + + + + + 100663671 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::GetTemporaryOutput() + + + + + + + + + + + 100663672 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::ConvertTemporaryToFinal() + + + + + + + + + + + + + + + + 100663673 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::MakeTemporaryCopy(System.IO.Stream) + + + + + + + + + + + + + 100663674 + System.IO.Stream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::OpenForDirectUpdate(System.IO.Stream) + + + + + + + + + + + + + + + + + + + + + + + + + 100663675 + System.Void ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::Dispose() + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.DescriptorData + + + + 100663676 + System.Int64 ICSharpCode.SharpZipLib.Zip.DescriptorData::get_CompressedSize() + + + + + + + + + + 100663677 + System.Void ICSharpCode.SharpZipLib.Zip.DescriptorData::set_CompressedSize(System.Int64) + + + + + + + + + + + 100663678 + System.Int64 ICSharpCode.SharpZipLib.Zip.DescriptorData::get_Size() + + + + + + + + + + 100663679 + System.Void ICSharpCode.SharpZipLib.Zip.DescriptorData::set_Size(System.Int64) + + + + + + + + + + + 100663680 + System.Int64 ICSharpCode.SharpZipLib.Zip.DescriptorData::get_Crc() + + + + + + + + + + 100663681 + System.Void ICSharpCode.SharpZipLib.Zip.DescriptorData::set_Crc(System.Int64) + + + + + + + + + + + 100663682 + System.Void ICSharpCode.SharpZipLib.Zip.DescriptorData::.ctor() + + + + + + + + + ICSharpCode.SharpZipLib.Zip.EntryPatchData + + + + 100663683 + System.Int64 ICSharpCode.SharpZipLib.Zip.EntryPatchData::get_SizePatchOffset() + + + + + + + + + + 100663684 + System.Void ICSharpCode.SharpZipLib.Zip.EntryPatchData::set_SizePatchOffset(System.Int64) + + + + + + + + + + + 100663685 + System.Int64 ICSharpCode.SharpZipLib.Zip.EntryPatchData::get_CrcPatchOffset() + + + + + + + + + + 100663686 + System.Void ICSharpCode.SharpZipLib.Zip.EntryPatchData::set_CrcPatchOffset(System.Int64) + + + + + + + + + + + 100663687 + System.Void ICSharpCode.SharpZipLib.Zip.EntryPatchData::.ctor() + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipHelperStream + + + + 100663690 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_IsStreamOwner() + + + + + + + + + + 100663691 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100663692 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_CanRead() + + + + + + + + + + 100663693 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_CanSeek() + + + + + + + + + + 100663694 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_CanTimeout() + + + + + + + + + + 100663695 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_Length() + + + + + + + + + + 100663696 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_Position() + + + + + + + + + + 100663697 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::set_Position(System.Int64) + + + + + + + + + + + 100663698 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_CanWrite() + + + + + + + + + + 100663688 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::.ctor(System.String) + + + + + + + + + + + + + 100663689 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::.ctor(System.IO.Stream) + + + + + + + + + + + + 100663699 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Flush() + + + + + + + + + + + 100663700 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + 100663701 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::SetLength(System.Int64) + + + + + + + + + + + 100663702 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100663703 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + 100663704 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Close() + + + + + + + + + + + + + + + + + + + + 100663705 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLocalHeader(ICSharpCode.SharpZipLib.Zip.ZipEntry,ICSharpCode.SharpZipLib.Zip.EntryPatchData) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663706 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::LocateBlockWithSignature(System.Int32,System.Int64,System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + 100663707 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteZip64EndOfCentralDirectory(System.Int64,System.Int64,System.Int64) + + + + + + + + + + + + + + + + + + + + + + + + + 100663708 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteEndOfCentralDirectory(System.Int64,System.Int64,System.Int64,System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663709 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::ReadLEShort() + + + + + + + + + + + + + + + + + + + + + 100663710 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::ReadLEInt() + + + + + + + + + + 100663711 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::ReadLELong() + + + + + + + + + + 100663712 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEShort(System.Int32) + + + + + + + + + + + + 100663713 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEUshort(System.UInt16) + + + + + + + + + + + + 100663714 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEInt(System.Int32) + + + + + + + + + + + + 100663715 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEUint(System.UInt32) + + + + + + + + + + + + 100663716 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLELong(System.Int64) + + + + + + + + + + + + 100663717 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEUlong(System.UInt64) + + + + + + + + + + + + 100663718 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteDataDescriptor(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663719 + System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::ReadDataDescriptor(System.Boolean,ICSharpCode.SharpZipLib.Zip.DescriptorData) + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipInputStream + + + + 100663722 + System.String ICSharpCode.SharpZipLib.Zip.ZipInputStream::get_Password() + + + + + + + + + + 100663723 + System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::set_Password(System.String) + + + + + + + + + + + 100663724 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipInputStream::get_CanDecompressEntry() + + + + + + + + + + 100663729 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::get_Available() + + + + + + + + + + + + + 100663730 + System.Int64 ICSharpCode.SharpZipLib.Zip.ZipInputStream::get_Length() + + + + + + + + + + + + + + + + + + + 100663720 + System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::.ctor(System.IO.Stream) + + + + + + + + + + + + + 100663721 + System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::.ctor(System.IO.Stream,System.Int32) + + + + + + + + + + + + + 100663725 + ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipInputStream::GetNextEntry() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663726 + System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::ReadDataDescriptor() + + + + + + + + + + + + + + + + + + + + + + + + + + 100663727 + System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::CompleteCloseEntry(System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663728 + System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::CloseEntry() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663731 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::ReadByte() + + + + + + + + + + + + + + + + 100663732 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::ReadingNotAvailable(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100663733 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::ReadingNotSupported(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100663734 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::InitialRead(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663735 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663736 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::BodyRead(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663737 + System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::Close() + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler + + + 100664559 + System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler::.ctor(System.Object,System.IntPtr) + + + + + 100664560 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler::Invoke(System.Byte[],System.Int32,System.Int32) + + + + + 100664561 + System.IAsyncResult ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler::BeginInvoke(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object) + + + + + 100664562 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipNameTransform + + + + 100663743 + System.String ICSharpCode.SharpZipLib.Zip.ZipNameTransform::get_TrimPrefix() + + + + + + + + + + 100663744 + System.Void ICSharpCode.SharpZipLib.Zip.ZipNameTransform::set_TrimPrefix(System.String) + + + + + + + + + + + + + + + + 100663738 + System.Void ICSharpCode.SharpZipLib.Zip.ZipNameTransform::.ctor() + + + + + + + + + + + 100663739 + System.Void ICSharpCode.SharpZipLib.Zip.ZipNameTransform::.ctor(System.String) + + + + + + + + + + + + 100663740 + System.Void ICSharpCode.SharpZipLib.Zip.ZipNameTransform::.cctor() + + + + + + + + + + + + + + + + + + + + + + + 100663741 + System.String ICSharpCode.SharpZipLib.Zip.ZipNameTransform::TransformDirectory(System.String) + + + + + + + + + + + + + + + + + + + + + 100663742 + System.String ICSharpCode.SharpZipLib.Zip.ZipNameTransform::TransformFile(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663745 + System.String ICSharpCode.SharpZipLib.Zip.ZipNameTransform::MakeValidName(System.String,System.Char) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663746 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipNameTransform::IsValidName(System.String,System.Boolean) + + + + + + + + + + + + + + + + + + + + + 100663747 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipNameTransform::IsValidName(System.String) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.ZipOutputStream + + + + 100663750 + System.Boolean ICSharpCode.SharpZipLib.Zip.ZipOutputStream::get_IsFinished() + + + + + + + + + + 100663754 + ICSharpCode.SharpZipLib.Zip.UseZip64 ICSharpCode.SharpZipLib.Zip.ZipOutputStream::get_UseZip64() + + + + + + + + + + 100663755 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::set_UseZip64(ICSharpCode.SharpZipLib.Zip.UseZip64) + + + + + + + + + + + 100663748 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::.ctor(System.IO.Stream) + + + + + + + + + + + + + + + + + + + 100663749 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::.ctor(System.IO.Stream,System.Int32) + + + + + + + + + + + + + + + + + + + 100663751 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::SetComment(System.String) + + + + + + + + + + + + + + + + + 100663752 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::SetLevel(System.Int32) + + + + + + + + + + + + 100663753 + System.Int32 ICSharpCode.SharpZipLib.Zip.ZipOutputStream::GetLevel() + + + + + + + + + + 100663756 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteLeShort(System.Int32) + + + + + + + + + + + + 100663757 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteLeInt(System.Int32) + + + + + + + + + + + + 100663758 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteLeLong(System.Int64) + + + + + + + + + + + + 100663759 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::PutNextEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663760 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::CloseEntry() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663761 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteEncryptionHeader(System.Int64) + + + + + + + + + + + + + + + + + + 100663762 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::AddExtraDataAES(ICSharpCode.SharpZipLib.Zip.ZipEntry,ICSharpCode.SharpZipLib.Zip.ZipExtraData) + + + + + + + + + + + + + + + + 100663763 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteAESHeader(ICSharpCode.SharpZipLib.Zip.ZipEntry) + + + + + + + + + + + + + 100663764 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663765 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::CopyAndEncrypt(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + 100663766 + System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::Finish() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.Deflater + + + + 100663771 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_Adler() + + + + + + + + + + 100663772 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_TotalIn() + + + + + + + + + + 100663773 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_TotalOut() + + + + + + + + + + 100663776 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_IsFinished() + + + + + + + + + + 100663777 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_IsNeedingInput() + + + + + + + + + + 100663767 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::.ctor() + + + + + + + + + + + 100663768 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::.ctor(System.Int32) + + + + + + + + + + + 100663769 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::.ctor(System.Int32,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663770 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Reset() + + + + + + + + + + + + + + + + + 100663774 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Flush() + + + + + + + + + + + 100663775 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Finish() + + + + + + + + + + + 100663778 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetInput(System.Byte[]) + + + + + + + + + + + 100663779 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetInput(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + 100663780 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetLevel(System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663781 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::GetLevel() + + + + + + + + + + 100663782 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetStrategy(ICSharpCode.SharpZipLib.Zip.Compression.DeflateStrategy) + + + + + + + + + + + 100663783 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Deflate(System.Byte[]) + + + + + + + + + + 100663784 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Deflate(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663785 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetDictionary(System.Byte[]) + + + + + + + + + + + 100663786 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetDictionary(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants + + + + 100663787 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants::.cctor() + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine + + + + 100663795 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::get_Adler() + + + + + + + + + + 100663796 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::get_TotalIn() + + + + + + + + + + 100663797 + ICSharpCode.SharpZipLib.Zip.Compression.DeflateStrategy ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::get_Strategy() + + + + + + + + + + 100663798 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::set_Strategy(ICSharpCode.SharpZipLib.Zip.Compression.DeflateStrategy) + + + + + + + + + + + 100663788 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::.ctor(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending) + + + + + + + + + + + + + + + + + + 100663789 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::Deflate(System.Boolean,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663790 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::SetInput(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663791 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::NeedsInput() + + + + + + + + + + 100663792 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::SetDictionary(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663793 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::Reset() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663794 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::ResetAdler() + + + + + + + + + + + 100663799 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::SetLevel(System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663800 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::FillWindow() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663801 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::UpdateHash() + + + + + + + + + + + 100663802 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::InsertString() + + + + + + + + + + + + + + 100663803 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::SlideWindow() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663804 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::FindLongestMatch(System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663805 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::DeflateStored(System.Boolean,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663806 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::DeflateFast(System.Boolean,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663807 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::DeflateSlow(System.Boolean,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman + + + + 100663808 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::.cctor() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663809 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::.ctor(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending) + + + + + + + + + + + + + + + + + 100663810 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::Reset() + + + + + + + + + + + + + + + 100663811 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::SendAllTrees(System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + 100663812 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::CompressBlock() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663813 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::FlushStoredBlock(System.Byte[],System.Int32,System.Int32,System.Boolean) + + + + + + + + + + + + + + + + + + + 100663814 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::FlushBlock(System.Byte[],System.Int32,System.Int32,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663815 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::IsFull() + + + + + + + + + + 100663816 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::TallyLit(System.Int32) + + + + + + + + + + + + + 100663817 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::TallyDist(System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663818 + System.Int16 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::BitReverse(System.Int32) + + + + + + + + + + 100663819 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::Lcode(System.Int32) + + + + + + + + + + + + + + + + + + + + + 100663820 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::Dcode(System.Int32) + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree + + + + 100664563 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::.ctor(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman,System.Int32,System.Int32,System.Int32) + + + + + + + + + + + + + + + + 100664564 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::Reset() + + + + + + + + + + + + + + + + + + + 100664565 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::WriteSymbol(System.Int32) + + + + + + + + + + + 100664566 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::CheckEmpty() + + + + + + + + + + + + + + + + + + + + + + 100664567 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::SetStaticCodes(System.Int16[],System.Byte[]) + + + + + + + + + + + + 100664568 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::BuildCodes() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664569 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::BuildTree() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664570 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::GetEncodedLength() + + + + + + + + + + + + + + + + + + 100664571 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::CalcBLFreq(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664572 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::WriteTree(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664573 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::BuildLength(System.Int32[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending + + + + 100663821 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending::.ctor() + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.Inflater + + + + 100663836 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_IsNeedingInput() + + + + + + + + + + 100663837 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_IsNeedingDictionary() + + + + + + + + + + 100663838 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_IsFinished() + + + + + + + + + + 100663839 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_Adler() + + + + + + + + + + 100663840 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_TotalOut() + + + + + + + + + + 100663841 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_TotalIn() + + + + + + + + + + 100663842 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_RemainingInput() + + + + + + + + + + 100663822 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::.ctor() + + + + + + + + + + + 100663823 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::.ctor(System.Boolean) + + + + + + + + + + + + + + + + + + + 100663824 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::Reset() + + + + + + + + + + + + + + + + + + + + + + + 100663825 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::DecodeHeader() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663826 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::DecodeDict() + + + + + + + + + + + + + + + + + + + + + + 100663827 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::DecodeHuffman() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663828 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::DecodeChksum() + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663829 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::Decode() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663830 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::SetDictionary(System.Byte[]) + + + + + + + + + + + 100663831 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::SetDictionary(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663832 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::SetInput(System.Byte[]) + + + + + + + + + + + 100663833 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::SetInput(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + 100663834 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::Inflate(System.Byte[]) + + + + + + + + + + + + + + + 100663835 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::Inflate(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663843 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::.cctor() + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader + + + + 100663844 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::Decode(ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663845 + ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::BuildLitLenTree() + + + + + + + + + + + + 100663846 + ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::BuildDistTree() + + + + + + + + + + + + 100663847 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::.ctor() + + + + + + + 100663848 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::.cctor() + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree + + + + 100663849 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree::.cctor() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663850 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree::.ctor(System.Byte[]) + + + + + + + + + + + + 100663851 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree::BuildTree(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663852 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree::GetSymbol(ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer + + + + 100663860 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::get_BitCount() + + + + + + + + + + 100663864 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::get_IsFlushed() + + + + + + + + + + 100663853 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::.ctor() + + + + + + + + + + + 100663854 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::.ctor(System.Int32) + + + + + + + + + + + + 100663855 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::Reset() + + + + + + + + + + + 100663856 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteByte(System.Int32) + + + + + + + + + + + 100663857 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteShort(System.Int32) + + + + + + + + + + + + 100663858 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteInt(System.Int32) + + + + + + + + + + + + + + 100663859 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteBlock(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + 100663861 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::AlignToByte() + + + + + + + + + + + + + + + + + + + + + 100663862 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteBits(System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + 100663863 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteShortMSB(System.Int32) + + + + + + + + + + + + 100663865 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::Flush(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663866 + System.Byte[] ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::ToByteArray() + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream + + + + 100663871 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_IsStreamOwner() + + + + + + + + + + 100663872 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100663873 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_CanPatchEntries() + + + + + + + + + + 100663874 + System.String ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_Password() + + + + + + + + + + 100663875 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::set_Password(System.String) + + + + + + + + + + + + + + + + + + + 100663880 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_CanRead() + + + + + + + + + + 100663881 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_CanSeek() + + + + + + + + + + 100663882 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_CanWrite() + + + + + + + + + + 100663883 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_Length() + + + + + + + + + + 100663884 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_Position() + + + + + + + + + + 100663885 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::set_Position(System.Int64) + + + + + + + + + + 100663867 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::.ctor(System.IO.Stream) + + + + + + + + + + + 100663868 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.Compression.Deflater) + + + + + + + + + + + 100663869 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.Compression.Deflater,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663870 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Finish() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663876 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::EncryptBlock(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + 100663877 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::InitializePassword(System.String) + + + + + + + + + + + + + 100663878 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::InitializeAESPassword(ICSharpCode.SharpZipLib.Zip.ZipEntry,System.String,System.Byte[]&,System.Byte[]&) + + + + + + + + + + + + + + + + + + + + 100663879 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Deflate() + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663886 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + 100663887 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::SetLength(System.Int64) + + + + + + + + + + 100663888 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::ReadByte() + + + + + + + + + + 100663889 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100663890 + System.IAsyncResult ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::BeginRead(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object) + + + + + + + + + + 100663891 + System.IAsyncResult ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::BeginWrite(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object) + + + + + + + + + + 100663892 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Flush() + + + + + + + + + + + + + 100663893 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Close() + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663894 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::GetAuthCodeIfAES() + + + + + + + + + + + + + + + 100663895 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::WriteByte(System.Byte) + + + + + + + + + + + + + 100663896 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer + + + + 100663899 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_RawLength() + + + + + + + + + + 100663900 + System.Byte[] ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_RawData() + + + + + + + + + + 100663901 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_ClearTextLength() + + + + + + + + + + 100663902 + System.Byte[] ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_ClearText() + + + + + + + + + + 100663903 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_Available() + + + + + + + + + + 100663904 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::set_Available(System.Int32) + + + + + + + + + + + 100663914 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::set_CryptoTransform(System.Security.Cryptography.ICryptoTransform) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663897 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::.ctor(System.IO.Stream) + + + + + + + + + + + 100663898 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::.ctor(System.IO.Stream,System.Int32) + + + + + + + + + + + + + + + + + + + 100663905 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::SetInflaterInput(ICSharpCode.SharpZipLib.Zip.Compression.Inflater) + + + + + + + + + + + + + + + + 100663906 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::Fill() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663907 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadRawBuffer(System.Byte[]) + + + + + + + + + + 100663908 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadRawBuffer(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663909 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadClearTextBuffer(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663910 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadLeByte() + + + + + + + + + + + + + + + + + + + + + 100663911 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadLeShort() + + + + + + + + + + 100663912 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadLeInt() + + + + + + + + + + 100663913 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadLeLong() + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream + + + + 100663918 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_IsStreamOwner() + + + + + + + + + + 100663919 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100663922 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_Available() + + + + + + + + + + + + + 100663924 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_CanRead() + + + + + + + + + + 100663925 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_CanSeek() + + + + + + + + + + 100663926 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_CanWrite() + + + + + + + + + + 100663927 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_Length() + + + + + + + + + + 100663928 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_Position() + + + + + + + + + + 100663929 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::set_Position(System.Int64) + + + + + + + + + + 100663915 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::.ctor(System.IO.Stream) + + + + + + + + + + + 100663916 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.Compression.Inflater) + + + + + + + + + + + 100663917 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.Compression.Inflater,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663920 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Skip(System.Int64) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663921 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::StopDecrypting() + + + + + + + + + + + 100663923 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Fill() + + + + + + + + + + + + + + + + + + + + 100663930 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Flush() + + + + + + + + + + + 100663931 + System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + 100663932 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::SetLength(System.Int64) + + + + + + + + + + 100663933 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100663934 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::WriteByte(System.Byte) + + + + + + + + + + 100663935 + System.IAsyncResult ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::BeginWrite(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object) + + + + + + + + + + 100663936 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Close() + + + + + + + + + + + + + + + + + + + 100663937 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow + + + + 100663938 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::Write(System.Int32) + + + + + + + + + + + + + + + + + 100663939 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::SlowRepeat(System.Int32,System.Int32,System.Int32) + + + + + + + + + + + + + + + + + 100663940 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::Repeat(System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663941 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::CopyStored(ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + 100663942 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::CopyDict(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + 100663943 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::GetFreeSpace() + + + + + + + + + + 100663944 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::GetAvailable() + + + + + + + + + + 100663945 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::CopyOutput(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663946 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::Reset() + + + + + + + + + + + 100663947 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::.ctor() + + + + + + + + + + + + ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator + + + + 100663951 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::get_AvailableBits() + + + + + + + + + + 100663952 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::get_AvailableBytes() + + + + + + + + + + 100663954 + System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::get_IsNeedingInput() + + + + + + + + + + 100663948 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::PeekBits(System.Int32) + + + + + + + + + + + + + + + + + + + + 100663949 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::DropBits(System.Int32) + + + + + + + + + + + + 100663950 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::GetBits(System.Int32) + + + + + + + + + + + + + + + + 100663953 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::SkipToByteBoundary() + + + + + + + + + + + + 100663955 + System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::CopyBytes(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663956 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::Reset() + + + + + + + + + + + + 100663957 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::SetInput(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663958 + System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::.ctor() + + + + + + + + + ICSharpCode.SharpZipLib.Tar.InvalidHeaderException + + + + 100663959 + System.Void ICSharpCode.SharpZipLib.Tar.InvalidHeaderException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) + + + + + + + + + + + 100663960 + System.Void ICSharpCode.SharpZipLib.Tar.InvalidHeaderException::.ctor() + + + + + + + + + + + 100663961 + System.Void ICSharpCode.SharpZipLib.Tar.InvalidHeaderException::.ctor(System.String) + + + + + + + + + + + 100663962 + System.Void ICSharpCode.SharpZipLib.Tar.InvalidHeaderException::.ctor(System.String,System.Exception) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler + + + 100663963 + System.Void ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler::.ctor(System.Object,System.IntPtr) + + + + + 100663964 + System.Void ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler::Invoke(ICSharpCode.SharpZipLib.Tar.TarArchive,ICSharpCode.SharpZipLib.Tar.TarEntry,System.String) + + + + + 100663965 + System.IAsyncResult ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler::BeginInvoke(ICSharpCode.SharpZipLib.Tar.TarArchive,ICSharpCode.SharpZipLib.Tar.TarEntry,System.String,System.AsyncCallback,System.Object) + + + + + 100663966 + System.Void ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Tar.TarArchive + + + + 100663978 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarArchive::get_AsciiTranslate() + + + + + + + + + + + + + + + 100663979 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_AsciiTranslate(System.Boolean) + + + + + + + + + + + + + + + + 100663981 + System.String ICSharpCode.SharpZipLib.Tar.TarArchive::get_PathPrefix() + + + + + + + + + + + + + + + 100663982 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_PathPrefix(System.String) + + + + + + + + + + + + + + + + 100663983 + System.String ICSharpCode.SharpZipLib.Tar.TarArchive::get_RootPath() + + + + + + + + + + + + + + + 100663984 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_RootPath(System.String) + + + + + + + + + + + + + + + + 100663986 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarArchive::get_ApplyUserInfoOverrides() + + + + + + + + + + + + + + + 100663987 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_ApplyUserInfoOverrides(System.Boolean) + + + + + + + + + + + + + + + + 100663988 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarArchive::get_UserId() + + + + + + + + + + + + + + + 100663989 + System.String ICSharpCode.SharpZipLib.Tar.TarArchive::get_UserName() + + + + + + + + + + + + + + + 100663990 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarArchive::get_GroupId() + + + + + + + + + + + + + + + 100663991 + System.String ICSharpCode.SharpZipLib.Tar.TarArchive::get_GroupName() + + + + + + + + + + + + + + + 100663992 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarArchive::get_RecordSize() + + + + + + + + + + + + + + + + + + + + + + + 100663993 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + + + + + + + 100663967 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::add_ProgressMessageEvent(ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler) + + + + + + + 100663968 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::remove_ProgressMessageEvent(ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler) + + + + + + + 100663969 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::OnProgressMessageEvent(ICSharpCode.SharpZipLib.Tar.TarEntry,System.String) + + + + + + + + + + + + + + + + 100663970 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::.ctor() + + + + + + + + + + + + + 100663971 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::.ctor(ICSharpCode.SharpZipLib.Tar.TarInputStream) + + + + + + + + + + + + + + + + + + + 100663972 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::.ctor(ICSharpCode.SharpZipLib.Tar.TarOutputStream) + + + + + + + + + + + + + + + + + + + 100663973 + ICSharpCode.SharpZipLib.Tar.TarArchive ICSharpCode.SharpZipLib.Tar.TarArchive::CreateInputTarArchive(System.IO.Stream) + + + + + + + + + + + + + + + + + + + + + + 100663974 + ICSharpCode.SharpZipLib.Tar.TarArchive ICSharpCode.SharpZipLib.Tar.TarArchive::CreateInputTarArchive(System.IO.Stream,System.Int32) + + + + + + + + + + + + + + + + + + + 100663975 + ICSharpCode.SharpZipLib.Tar.TarArchive ICSharpCode.SharpZipLib.Tar.TarArchive::CreateOutputTarArchive(System.IO.Stream) + + + + + + + + + + + + + + + + + + + + + + 100663976 + ICSharpCode.SharpZipLib.Tar.TarArchive ICSharpCode.SharpZipLib.Tar.TarArchive::CreateOutputTarArchive(System.IO.Stream,System.Int32) + + + + + + + + + + + + + + + + + + + 100663977 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::SetKeepOldFiles(System.Boolean) + + + + + + + + + + + + + + + + 100663980 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::SetAsciiTranslation(System.Boolean) + + + + + + + + + + + + + + + + 100663985 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::SetUserInfo(System.Int32,System.String,System.Int32,System.String) + + + + + + + + + + + + + + + + + + + + 100663994 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::CloseArchive() + + + + + + + + + + + 100663995 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::ListContents() + + + + + + + + + + + + + + + + + + + + + 100663996 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::ExtractContents(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + 100663997 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::ExtractEntry(System.String,ICSharpCode.SharpZipLib.Tar.TarEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663998 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::WriteEntry(ICSharpCode.SharpZipLib.Tar.TarEntry,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100663999 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::WriteEntryCore(ICSharpCode.SharpZipLib.Tar.TarEntry,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664000 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::Dispose() + + + + + + + + + + + + 100664001 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::Dispose(System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664002 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::Close() + + + + + + + + + + + 100664003 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::Finalize() + + + + + + + + + + + + 100664004 + System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::EnsureDirectoryExists(System.String) + + + + + + + + + + + + + + + + + + 100664005 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarArchive::IsBinary(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Tar.TarBuffer + + + + 100664006 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::get_RecordSize() + + + + + + + + + + 100664008 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::get_BlockFactor() + + + + + + + + + + 100664021 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::get_CurrentBlock() + + + + + + + + + + 100664022 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarBuffer::get_IsStreamOwner() + + + + + + + + + + 100664023 + System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100664025 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::get_CurrentRecord() + + + + + + + + + + 100664007 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::GetRecordSize() + + + + + + + + + + 100664009 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::GetBlockFactor() + + + + + + + + + + 100664010 + System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::.ctor() + + + + + + + + + + + + + + 100664011 + ICSharpCode.SharpZipLib.Tar.TarBuffer ICSharpCode.SharpZipLib.Tar.TarBuffer::CreateInputTarBuffer(System.IO.Stream) + + + + + + + + + + + + + + + 100664012 + ICSharpCode.SharpZipLib.Tar.TarBuffer ICSharpCode.SharpZipLib.Tar.TarBuffer::CreateInputTarBuffer(System.IO.Stream,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + 100664013 + ICSharpCode.SharpZipLib.Tar.TarBuffer ICSharpCode.SharpZipLib.Tar.TarBuffer::CreateOutputTarBuffer(System.IO.Stream) + + + + + + + + + + + + + + + 100664014 + ICSharpCode.SharpZipLib.Tar.TarBuffer ICSharpCode.SharpZipLib.Tar.TarBuffer::CreateOutputTarBuffer(System.IO.Stream,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + 100664015 + System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::Initialize(System.Int32) + + + + + + + + + + + + + + + + + + + + + + 100664016 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarBuffer::IsEOFBlock(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664017 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarBuffer::IsEndOfArchiveBlock(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664018 + System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::SkipBlock() + + + + + + + + + + + + + + + + + + + + + + + 100664019 + System.Byte[] ICSharpCode.SharpZipLib.Tar.TarBuffer::ReadBlock() + + + + + + + + + + + + + + + + + + + + + + + + + 100664020 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarBuffer::ReadRecord() + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664024 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::GetCurrentBlockNum() + + + + + + + + + + 100664026 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::GetCurrentRecordNum() + + + + + + + + + + 100664027 + System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::WriteBlock(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664028 + System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::WriteBlock(System.Byte[],System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664029 + System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::WriteRecord() + + + + + + + + + + + + + + + + + + + 100664030 + System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::WriteFinalRecord() + + + + + + + + + + + + + + + + + + + + + + 100664031 + System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::Close() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Tar.TarEntry + + + + 100664041 + ICSharpCode.SharpZipLib.Tar.TarHeader ICSharpCode.SharpZipLib.Tar.TarEntry::get_TarHeader() + + + + + + + + + + 100664042 + System.String ICSharpCode.SharpZipLib.Tar.TarEntry::get_Name() + + + + + + + + + + 100664043 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_Name(System.String) + + + + + + + + + + + 100664044 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarEntry::get_UserId() + + + + + + + + + + 100664045 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_UserId(System.Int32) + + + + + + + + + + + 100664046 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarEntry::get_GroupId() + + + + + + + + + + 100664047 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_GroupId(System.Int32) + + + + + + + + + + + 100664048 + System.String ICSharpCode.SharpZipLib.Tar.TarEntry::get_UserName() + + + + + + + + + + 100664049 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_UserName(System.String) + + + + + + + + + + + 100664050 + System.String ICSharpCode.SharpZipLib.Tar.TarEntry::get_GroupName() + + + + + + + + + + 100664051 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_GroupName(System.String) + + + + + + + + + + + 100664054 + System.DateTime ICSharpCode.SharpZipLib.Tar.TarEntry::get_ModTime() + + + + + + + + + + 100664055 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_ModTime(System.DateTime) + + + + + + + + + + + 100664056 + System.String ICSharpCode.SharpZipLib.Tar.TarEntry::get_File() + + + + + + + + + + 100664057 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarEntry::get_Size() + + + + + + + + + + 100664058 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_Size(System.Int64) + + + + + + + + + + + 100664059 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarEntry::get_IsDirectory() + + + + + + + + + + + + + + + + + + + + + + + + 100664032 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::.ctor() + + + + + + + + + + + + 100664033 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::.ctor(System.Byte[]) + + + + + + + + + + + + + 100664034 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::.ctor(ICSharpCode.SharpZipLib.Tar.TarHeader) + + + + + + + + + + + + + + + + + 100664035 + System.Object ICSharpCode.SharpZipLib.Tar.TarEntry::Clone() + + + + + + + + + + + + + + 100664036 + ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarEntry::CreateTarEntry(System.String) + + + + + + + + + + + + 100664037 + ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarEntry::CreateEntryFromFile(System.String) + + + + + + + + + + + + 100664038 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarEntry::Equals(System.Object) + + + + + + + + + + + + + + + + 100664039 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarEntry::GetHashCode() + + + + + + + + + + 100664040 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarEntry::IsDescendent(ICSharpCode.SharpZipLib.Tar.TarEntry) + + + + + + + + + + + + + + + 100664052 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::SetIds(System.Int32,System.Int32) + + + + + + + + + + + + 100664053 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::SetNames(System.String,System.String) + + + + + + + + + + + + 100664060 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::GetFileTarHeader(ICSharpCode.SharpZipLib.Tar.TarHeader,System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664061 + ICSharpCode.SharpZipLib.Tar.TarEntry[] ICSharpCode.SharpZipLib.Tar.TarEntry::GetDirectoryEntries() + + + + + + + + + + + + + + + + + + + + + + + + + 100664062 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::WriteEntryHeader(System.Byte[]) + + + + + + + + + + + 100664063 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::AdjustEntryName(System.Byte[],System.String) + + + + + + + + + + + 100664064 + System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::NameTarHeader(ICSharpCode.SharpZipLib.Tar.TarHeader,System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Tar.TarException + + + + 100664065 + System.Void ICSharpCode.SharpZipLib.Tar.TarException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) + + + + + + + + + + + 100664066 + System.Void ICSharpCode.SharpZipLib.Tar.TarException::.ctor() + + + + + + + + + + + 100664067 + System.Void ICSharpCode.SharpZipLib.Tar.TarException::.ctor(System.String) + + + + + + + + + + + 100664068 + System.Void ICSharpCode.SharpZipLib.Tar.TarException::.ctor(System.String,System.Exception) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Tar.TarHeader + + + + 100664070 + System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_Name() + + + + + + + + + + 100664071 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Name(System.String) + + + + + + + + + + + + + + + + 100664073 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_Mode() + + + + + + + + + + 100664074 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Mode(System.Int32) + + + + + + + + + + + 100664075 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_UserId() + + + + + + + + + + 100664076 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_UserId(System.Int32) + + + + + + + + + + + 100664077 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_GroupId() + + + + + + + + + + 100664078 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_GroupId(System.Int32) + + + + + + + + + + + 100664079 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarHeader::get_Size() + + + + + + + + + + 100664080 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Size(System.Int64) + + + + + + + + + + + + + + + + 100664081 + System.DateTime ICSharpCode.SharpZipLib.Tar.TarHeader::get_ModTime() + + + + + + + + + + 100664082 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_ModTime(System.DateTime) + + + + + + + + + + + + + + + + 100664083 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_Checksum() + + + + + + + + + + 100664084 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarHeader::get_IsChecksumValid() + + + + + + + + + + 100664085 + System.Byte ICSharpCode.SharpZipLib.Tar.TarHeader::get_TypeFlag() + + + + + + + + + + 100664086 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_TypeFlag(System.Byte) + + + + + + + + + + + 100664087 + System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_LinkName() + + + + + + + + + + 100664088 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_LinkName(System.String) + + + + + + + + + + + + + + + + 100664089 + System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_Magic() + + + + + + + + + + 100664090 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Magic(System.String) + + + + + + + + + + + + + + + + 100664091 + System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_Version() + + + + + + + + + + 100664092 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Version(System.String) + + + + + + + + + + + + + + + + 100664093 + System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_UserName() + + + + + + + + + + 100664094 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_UserName(System.String) + + + + + + + + + + + + + + + + + + + + + + 100664095 + System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_GroupName() + + + + + + + + + + 100664096 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_GroupName(System.String) + + + + + + + + + + + + + + + + + 100664097 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_DevMajor() + + + + + + + + + + 100664098 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_DevMajor(System.Int32) + + + + + + + + + + + 100664099 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_DevMinor() + + + + + + + + + + 100664100 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_DevMinor(System.Int32) + + + + + + + + + + + 100664069 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::.ctor() + + + + + + + + + + + + + + + + + + + + 100664072 + System.String ICSharpCode.SharpZipLib.Tar.TarHeader::GetName() + + + + + + + + + + 100664101 + System.Object ICSharpCode.SharpZipLib.Tar.TarHeader::Clone() + + + + + + + + + + 100664102 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::ParseBuffer(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664103 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::WriteHeader(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664104 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetHashCode() + + + + + + + + + + 100664105 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarHeader::Equals(System.Object) + + + + + + + + + + + + + + + + + + 100664106 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::SetValueDefaults(System.Int32,System.String,System.Int32,System.String) + + + + + + + + + + + + + + 100664107 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::RestoreSetValues() + + + + + + + + + + + + + + 100664108 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarHeader::ParseBinaryOrOctal(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + 100664109 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarHeader::ParseOctal(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664110 + System.Text.StringBuilder ICSharpCode.SharpZipLib.Tar.TarHeader::ParseName(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664111 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetNameBytes(System.Text.StringBuilder,System.Int32,System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + 100664112 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetNameBytes(System.String,System.Int32,System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664113 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetNameBytes(System.Text.StringBuilder,System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + 100664114 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetNameBytes(System.String,System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + 100664115 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetAsciiBytes(System.String,System.Int32,System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664116 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetOctalBytes(System.Int64,System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664117 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetBinaryOrOctalBytes(System.Int64,System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + 100664118 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::GetCheckSumOctalBytes(System.Int64,System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + 100664119 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::ComputeCheckSum(System.Byte[]) + + + + + + + + + + + + + + + + + + 100664120 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::MakeCheckSum(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664121 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetCTime(System.DateTime) + + + + + + + + + + 100664122 + System.DateTime ICSharpCode.SharpZipLib.Tar.TarHeader::GetDateTimeFromCTime(System.Int64) + + + + + + + + + + + + + + + 100664123 + System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::.cctor() + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Tar.TarInputStream + + + + 100664126 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_IsStreamOwner() + + + + + + + + + + 100664127 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100664128 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_CanRead() + + + + + + + + + + 100664129 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_CanSeek() + + + + + + + + + + 100664130 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_CanWrite() + + + + + + + + + + 100664131 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarInputStream::get_Length() + + + + + + + + + + 100664132 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarInputStream::get_Position() + + + + + + + + + + 100664133 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::set_Position(System.Int64) + + + + + + + + + + 100664143 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarInputStream::get_RecordSize() + + + + + + + + + + 100664145 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarInputStream::get_Available() + + + + + + + + + + 100664147 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_IsMarkSupported() + + + + + + + + + + 100664124 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::.ctor(System.IO.Stream) + + + + + + + + + + + 100664125 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::.ctor(System.IO.Stream,System.Int32) + + + + + + + + + + + + + 100664134 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Flush() + + + + + + + + + + + 100664135 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarInputStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + 100664136 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::SetLength(System.Int64) + + + + + + + + + + 100664137 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100664138 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::WriteByte(System.Byte) + + + + + + + + + + 100664139 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarInputStream::ReadByte() + + + + + + + + + + + + + + + + + 100664140 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarInputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664141 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Close() + + + + + + + + + + + 100664142 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::SetEntryFactory(ICSharpCode.SharpZipLib.Tar.TarInputStream/IEntryFactory) + + + + + + + + + + + 100664144 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarInputStream::GetRecordSize() + + + + + + + + + + 100664146 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Skip(System.Int64) + + + + + + + + + + + + + + + + + + + + + + + + 100664148 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Mark(System.Int32) + + + + + + + + + + 100664149 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Reset() + + + + + + + + + + 100664150 + ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarInputStream::GetNextEntry() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664151 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::CopyEntryContents(System.IO.Stream) + + + + + + + + + + + + + + + + + + 100664152 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::SkipToNextEntry() + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Tar.TarInputStream/EntryFactoryAdapter + + + + 100664577 + ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarInputStream/EntryFactoryAdapter::CreateEntry(System.String) + + + + + + + + + + 100664578 + ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarInputStream/EntryFactoryAdapter::CreateEntryFromFile(System.String) + + + + + + + + + + 100664579 + ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarInputStream/EntryFactoryAdapter::CreateEntry(System.Byte[]) + + + + + + + + + + 100664580 + System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream/EntryFactoryAdapter::.ctor() + + + + + + + + + ICSharpCode.SharpZipLib.Tar.TarOutputStream + + + + 100664155 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_IsStreamOwner() + + + + + + + + + + 100664156 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100664157 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_CanRead() + + + + + + + + + + 100664158 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_CanSeek() + + + + + + + + + + 100664159 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_CanWrite() + + + + + + + + + + 100664160 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_Length() + + + + + + + + + + 100664161 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_Position() + + + + + + + + + + 100664162 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::set_Position(System.Int64) + + + + + + + + + + + 100664170 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_RecordSize() + + + + + + + + + + 100664172 + System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_IsEntryOpen() + + + + + + + + + + 100664153 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::.ctor(System.IO.Stream) + + + + + + + + + + + 100664154 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::.ctor(System.IO.Stream,System.Int32) + + + + + + + + + + + + + + + + + + + + 100664163 + System.Int64 ICSharpCode.SharpZipLib.Tar.TarOutputStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + 100664164 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::SetLength(System.Int64) + + + + + + + + + + + 100664165 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarOutputStream::ReadByte() + + + + + + + + + + 100664166 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarOutputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100664167 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::Flush() + + + + + + + + + + + 100664168 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::Finish() + + + + + + + + + + + + + + + + 100664169 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::Close() + + + + + + + + + + + + + + + + + 100664171 + System.Int32 ICSharpCode.SharpZipLib.Tar.TarOutputStream::GetRecordSize() + + + + + + + + + + 100664173 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::PutNextEntry(ICSharpCode.SharpZipLib.Tar.TarEntry) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664174 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::CloseEntry() + + + + + + + + + + + + + + + + + + + + + + + 100664175 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::WriteByte(System.Byte) + + + + + + + + + + + 100664176 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664177 + System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::WriteEofBlock() + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Lzw.LzwConstants + + + + 100664178 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwConstants::.ctor() + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Lzw.LzwException + + + + 100664179 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) + + + + + + + + + + + 100664180 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwException::.ctor() + + + + + + + + + + + 100664181 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwException::.ctor(System.String) + + + + + + + + + + + 100664182 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwException::.ctor(System.String,System.Exception) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Lzw.LzwInputStream + + + + 100664183 + System.Boolean ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_IsStreamOwner() + + + + + + + + + + 100664184 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100664191 + System.Boolean ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_CanRead() + + + + + + + + + + 100664192 + System.Boolean ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_CanSeek() + + + + + + + + + + 100664193 + System.Boolean ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_CanWrite() + + + + + + + + + + 100664194 + System.Int64 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_Length() + + + + + + + + + + 100664195 + System.Int64 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_Position() + + + + + + + + + + 100664196 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::set_Position(System.Int64) + + + + + + + + + + 100664185 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::.ctor(System.IO.Stream) + + + + + + + + + + + + + + + + 100664186 + System.Int32 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::ReadByte() + + + + + + + + + + + + + + + + 100664187 + System.Int32 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664188 + System.Int32 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::ResetBuf(System.Int32) + + + + + + + + + + + + + 100664189 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Fill() + + + + + + + + + + + + + + + + 100664190 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::ParseHeader() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664197 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Flush() + + + + + + + + + + + 100664198 + System.Int64 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + 100664199 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::SetLength(System.Int64) + + + + + + + + + + 100664200 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100664201 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::WriteByte(System.Byte) + + + + + + + + + + 100664202 + System.IAsyncResult ICSharpCode.SharpZipLib.Lzw.LzwInputStream::BeginWrite(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object) + + + + + + + + + + 100664203 + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Close() + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.GZip.GZip + + + + 100664204 + System.Void ICSharpCode.SharpZipLib.GZip.GZip::Decompress(System.IO.Stream,System.IO.Stream,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + 100664205 + System.Void ICSharpCode.SharpZipLib.GZip.GZip::Compress(System.IO.Stream,System.IO.Stream,System.Boolean,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.GZip.GZipConstants + + + + 100664206 + System.Void ICSharpCode.SharpZipLib.GZip.GZipConstants::.ctor() + + + + + + + + + + + + + ICSharpCode.SharpZipLib.GZip.GZipException + + + + 100664207 + System.Void ICSharpCode.SharpZipLib.GZip.GZipException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) + + + + + + + + + + + 100664208 + System.Void ICSharpCode.SharpZipLib.GZip.GZipException::.ctor() + + + + + + + + + + + 100664209 + System.Void ICSharpCode.SharpZipLib.GZip.GZipException::.ctor(System.String) + + + + + + + + + + + 100664210 + System.Void ICSharpCode.SharpZipLib.GZip.GZipException::.ctor(System.String,System.Exception) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.GZip.GZipInputStream + + + + 100664211 + System.Void ICSharpCode.SharpZipLib.GZip.GZipInputStream::.ctor(System.IO.Stream) + + + + + + + + + + + 100664212 + System.Void ICSharpCode.SharpZipLib.GZip.GZipInputStream::.ctor(System.IO.Stream,System.Int32) + + + + + + + + + + + 100664213 + System.Int32 ICSharpCode.SharpZipLib.GZip.GZipInputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664214 + System.Boolean ICSharpCode.SharpZipLib.GZip.GZipInputStream::ReadHeader() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664215 + System.Void ICSharpCode.SharpZipLib.GZip.GZipInputStream::ReadFooter() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.GZip.GZipOutputStream + + + + 100664216 + System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::.ctor(System.IO.Stream) + + + + + + + + + + + 100664217 + System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::.ctor(System.IO.Stream,System.Int32) + + + + + + + + + + + + 100664218 + System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::Finalize() + + + + + + + + + + + + 100664219 + System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::SetLevel(System.Int32) + + + + + + + + + + + + + + + + 100664220 + System.Int32 ICSharpCode.SharpZipLib.GZip.GZipOutputStream::GetLevel() + + + + + + + + + + 100664221 + System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + 100664222 + System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::Close() + + + + + + + + + + + + + + + + + + + + + + 100664223 + System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::Finish() + + + + + + + + + + + + + + + + + + + + + + + + 100664224 + System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::WriteHeader() + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Encryption.PkzipClassic + + + + 100664225 + System.Byte[] ICSharpCode.SharpZipLib.Encryption.PkzipClassic::GenerateKeys(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664226 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassic::.ctor() + + + + + + + + + ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase + + + + 100664227 + System.Byte ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::TransformByte() + + + + + + + + + + + 100664228 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::SetKeys(System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + 100664229 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::UpdateKeys(System.Byte) + + + + + + + + + + + + + + 100664230 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::Reset() + + + + + + + + + + + + + 100664231 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::.ctor() + + + + + + + + + ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform + + + + 100664235 + System.Boolean ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::get_CanReuseTransform() + + + + + + + + + + 100664236 + System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::get_InputBlockSize() + + + + + + + + + + 100664237 + System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::get_OutputBlockSize() + + + + + + + + + + 100664238 + System.Boolean ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::get_CanTransformMultipleBlocks() + + + + + + + + + + 100664232 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::.ctor(System.Byte[]) + + + + + + + + + + + + 100664233 + System.Byte[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::TransformFinalBlock(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + 100664234 + System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::TransformBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32) + + + + + + + + + + + + + + + + + + + 100664239 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::Dispose() + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform + + + + 100664243 + System.Boolean ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::get_CanReuseTransform() + + + + + + + + + + 100664244 + System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::get_InputBlockSize() + + + + + + + + + + 100664245 + System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::get_OutputBlockSize() + + + + + + + + + + 100664246 + System.Boolean ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::get_CanTransformMultipleBlocks() + + + + + + + + + + 100664240 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::.ctor(System.Byte[]) + + + + + + + + + + + + 100664241 + System.Byte[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::TransformFinalBlock(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + 100664242 + System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::TransformBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32) + + + + + + + + + + + + + + + + + + + 100664247 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::Dispose() + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged + + + + 100664248 + System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::get_BlockSize() + + + + + + + + + + 100664249 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::set_BlockSize(System.Int32) + + + + + + + + + + + + + + + 100664250 + System.Security.Cryptography.KeySizes[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::get_LegalKeySizes() + + + + + + + + + + + + 100664252 + System.Security.Cryptography.KeySizes[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::get_LegalBlockSizes() + + + + + + + + + + + + 100664253 + System.Byte[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::get_Key() + + + + + + + + + + + + + + + 100664254 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::set_Key(System.Byte[]) + + + + + + + + + + + + + + + + + + + + 100664251 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::GenerateIV() + + + + + + + + + + 100664255 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::GenerateKey() + + + + + + + + + + + + + 100664256 + System.Security.Cryptography.ICryptoTransform ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::CreateEncryptor(System.Byte[],System.Byte[]) + + + + + + + + + + + 100664257 + System.Security.Cryptography.ICryptoTransform ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::CreateDecryptor(System.Byte[],System.Byte[]) + + + + + + + + + + + 100664258 + System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::.ctor() + + + + + + + + + ICSharpCode.SharpZipLib.Encryption.ZipAESStream + + + + 100664259 + System.Void ICSharpCode.SharpZipLib.Encryption.ZipAESStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Encryption.ZipAESTransform,System.Security.Cryptography.CryptoStreamMode) + + + + + + + + + + + + + + + + + + + + 100664260 + System.Int32 ICSharpCode.SharpZipLib.Encryption.ZipAESStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664261 + System.Void ICSharpCode.SharpZipLib.Encryption.ZipAESStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + ICSharpCode.SharpZipLib.Encryption.ZipAESTransform + + + + 100664264 + System.Byte[] ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_PwdVerifier() + + + + + + + + + + 100664267 + System.Int32 ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_InputBlockSize() + + + + + + + + + + 100664268 + System.Int32 ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_OutputBlockSize() + + + + + + + + + + 100664269 + System.Boolean ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_CanTransformMultipleBlocks() + + + + + + + + + + 100664270 + System.Boolean ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_CanReuseTransform() + + + + + + + + + + 100664262 + System.Void ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::.ctor(System.String,System.Byte[],System.Int32,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664263 + System.Int32 ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::TransformBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664265 + System.Byte[] ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::GetAuthCode() + + + + + + + + + + + + + + + + + 100664266 + System.Byte[] ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::TransformFinalBlock(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100664271 + System.Void ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::Dispose() + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.ScanEventArgs + + + + 100664273 + System.String ICSharpCode.SharpZipLib.Core.ScanEventArgs::get_Name() + + + + + + + + + + 100664274 + System.Boolean ICSharpCode.SharpZipLib.Core.ScanEventArgs::get_ContinueRunning() + + + + + + + + + + 100664275 + System.Void ICSharpCode.SharpZipLib.Core.ScanEventArgs::set_ContinueRunning(System.Boolean) + + + + + + + + + + + 100664272 + System.Void ICSharpCode.SharpZipLib.Core.ScanEventArgs::.ctor(System.String) + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.ProgressEventArgs + + + + 100664277 + System.String ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_Name() + + + + + + + + + + 100664278 + System.Boolean ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_ContinueRunning() + + + + + + + + + + 100664279 + System.Void ICSharpCode.SharpZipLib.Core.ProgressEventArgs::set_ContinueRunning(System.Boolean) + + + + + + + + + + + 100664280 + System.Single ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_PercentComplete() + + + + + + + + + + + + + + + + + 100664281 + System.Int64 ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_Processed() + + + + + + + + + + 100664282 + System.Int64 ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_Target() + + + + + + + + + + 100664276 + System.Void ICSharpCode.SharpZipLib.Core.ProgressEventArgs::.ctor(System.String,System.Int64,System.Int64) + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.DirectoryEventArgs + + + + 100664284 + System.Boolean ICSharpCode.SharpZipLib.Core.DirectoryEventArgs::get_HasMatchingFiles() + + + + + + + + + + 100664283 + System.Void ICSharpCode.SharpZipLib.Core.DirectoryEventArgs::.ctor(System.String,System.Boolean) + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs + + + + 100664286 + System.String ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::get_Name() + + + + + + + + + + 100664287 + System.Exception ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::get_Exception() + + + + + + + + + + 100664288 + System.Boolean ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::get_ContinueRunning() + + + + + + + + + + 100664289 + System.Void ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::set_ContinueRunning(System.Boolean) + + + + + + + + + + + 100664285 + System.Void ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::.ctor(System.String,System.Exception) + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.ProcessFileHandler + + + 100664290 + System.Void ICSharpCode.SharpZipLib.Core.ProcessFileHandler::.ctor(System.Object,System.IntPtr) + + + + + 100664291 + System.Void ICSharpCode.SharpZipLib.Core.ProcessFileHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanEventArgs) + + + + + 100664292 + System.IAsyncResult ICSharpCode.SharpZipLib.Core.ProcessFileHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanEventArgs,System.AsyncCallback,System.Object) + + + + + 100664293 + System.Void ICSharpCode.SharpZipLib.Core.ProcessFileHandler::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Core.ProgressHandler + + + 100664294 + System.Void ICSharpCode.SharpZipLib.Core.ProgressHandler::.ctor(System.Object,System.IntPtr) + + + + + 100664295 + System.Void ICSharpCode.SharpZipLib.Core.ProgressHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ProgressEventArgs) + + + + + 100664296 + System.IAsyncResult ICSharpCode.SharpZipLib.Core.ProgressHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ProgressEventArgs,System.AsyncCallback,System.Object) + + + + + 100664297 + System.Void ICSharpCode.SharpZipLib.Core.ProgressHandler::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Core.CompletedFileHandler + + + 100664298 + System.Void ICSharpCode.SharpZipLib.Core.CompletedFileHandler::.ctor(System.Object,System.IntPtr) + + + + + 100664299 + System.Void ICSharpCode.SharpZipLib.Core.CompletedFileHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanEventArgs) + + + + + 100664300 + System.IAsyncResult ICSharpCode.SharpZipLib.Core.CompletedFileHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanEventArgs,System.AsyncCallback,System.Object) + + + + + 100664301 + System.Void ICSharpCode.SharpZipLib.Core.CompletedFileHandler::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler + + + 100664302 + System.Void ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler::.ctor(System.Object,System.IntPtr) + + + + + 100664303 + System.Void ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs) + + + + + 100664304 + System.IAsyncResult ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs,System.AsyncCallback,System.Object) + + + + + 100664305 + System.Void ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Core.FileFailureHandler + + + 100664306 + System.Void ICSharpCode.SharpZipLib.Core.FileFailureHandler::.ctor(System.Object,System.IntPtr) + + + + + 100664307 + System.Void ICSharpCode.SharpZipLib.Core.FileFailureHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs) + + + + + 100664308 + System.IAsyncResult ICSharpCode.SharpZipLib.Core.FileFailureHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs,System.AsyncCallback,System.Object) + + + + + 100664309 + System.Void ICSharpCode.SharpZipLib.Core.FileFailureHandler::EndInvoke(System.IAsyncResult) + + + + + + + + ICSharpCode.SharpZipLib.Core.FileSystemScanner + + + + 100664310 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::.ctor(System.String) + + + + + + + + + + + + 100664311 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::.ctor(System.String,System.String) + + + + + + + + + + + + + 100664312 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::.ctor(ICSharpCode.SharpZipLib.Core.IScanFilter) + + + + + + + + + + + + 100664313 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::.ctor(ICSharpCode.SharpZipLib.Core.IScanFilter,ICSharpCode.SharpZipLib.Core.IScanFilter) + + + + + + + + + + + + + 100664314 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::add_ProcessDirectory(System.EventHandler`1<ICSharpCode.SharpZipLib.Core.DirectoryEventArgs>) + + + + + + + 100664315 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::remove_ProcessDirectory(System.EventHandler`1<ICSharpCode.SharpZipLib.Core.DirectoryEventArgs>) + + + + + + + 100664316 + System.Boolean ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnDirectoryFailure(System.String,System.Exception) + + + + + + + + + + + + + + + + + + + 100664317 + System.Boolean ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnFileFailure(System.String,System.Exception) + + + + + + + + + + + + + + + + + + + 100664318 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnProcessFile(System.String) + + + + + + + + + + + + + + + + + + 100664319 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnCompleteFile(System.String) + + + + + + + + + + + + + + + + + + 100664320 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnProcessDirectory(System.String,System.Boolean) + + + + + + + + + + + + + + + + + + 100664321 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::Scan(System.String,System.Boolean) + + + + + + + + + + + + 100664322 + System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::ScanDir(System.String,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.NameFilter + + + + 100664326 + System.Void ICSharpCode.SharpZipLib.Core.NameFilter::.ctor(System.String) + + + + + + + + + + + + + + + 100664327 + System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsValidExpression(System.String) + + + + + + + + + + + + + + + + 100664328 + System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsValidFilterExpression(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664329 + System.String[] ICSharpCode.SharpZipLib.Core.NameFilter::SplitQuoted(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664330 + System.String ICSharpCode.SharpZipLib.Core.NameFilter::ToString() + + + + + + + + + + 100664331 + System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsIncluded(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + 100664332 + System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsExcluded(System.String) + + + + + + + + + + + + + + + + + + + + 100664333 + System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsMatch(System.String) + + + + + + + + + + 100664334 + System.Void ICSharpCode.SharpZipLib.Core.NameFilter::Compile() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.PathFilter + + + + 100664335 + System.Void ICSharpCode.SharpZipLib.Core.PathFilter::.ctor(System.String) + + + + + + + + + + + + 100664336 + System.Boolean ICSharpCode.SharpZipLib.Core.PathFilter::IsMatch(System.String) + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.ExtendedPathFilter + + + + 100664341 + System.Int64 ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::get_MinSize() + + + + + + + + + + 100664342 + System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::set_MinSize(System.Int64) + + + + + + + + + + + + + + + + + + 100664343 + System.Int64 ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::get_MaxSize() + + + + + + + + + + 100664344 + System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::set_MaxSize(System.Int64) + + + + + + + + + + + + + + + + + + 100664345 + System.DateTime ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::get_MinDate() + + + + + + + + + + 100664346 + System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::set_MinDate(System.DateTime) + + + + + + + + + + + + + + + + 100664347 + System.DateTime ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::get_MaxDate() + + + + + + + + + + 100664348 + System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::set_MaxDate(System.DateTime) + + + + + + + + + + + + + + + + 100664337 + System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::.ctor(System.String,System.Int64,System.Int64) + + + + + + + + + + + + + + + + 100664338 + System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::.ctor(System.String,System.DateTime,System.DateTime) + + + + + + + + + + + + + + + + 100664339 + System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::.ctor(System.String,System.Int64,System.Int64,System.DateTime,System.DateTime) + + + + + + + + + + + + + + + + + + 100664340 + System.Boolean ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::IsMatch(System.String) + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.NameAndSizeFilter + + + + 100664351 + System.Int64 ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::get_MinSize() + + + + + + + + + + 100664352 + System.Void ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::set_MinSize(System.Int64) + + + + + + + + + + + + + + + + + + 100664353 + System.Int64 ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::get_MaxSize() + + + + + + + + + + 100664354 + System.Void ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::set_MaxSize(System.Int64) + + + + + + + + + + + + + + + + + + 100664349 + System.Void ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::.ctor(System.String,System.Int64,System.Int64) + + + + + + + + + + + + + + 100664350 + System.Boolean ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::IsMatch(System.String) + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.StreamUtils + + + + 100664355 + System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::ReadFully(System.IO.Stream,System.Byte[]) + + + + + + + + + + + 100664356 + System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::ReadFully(System.IO.Stream,System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664357 + System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::Copy(System.IO.Stream,System.IO.Stream,System.Byte[]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664358 + System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::Copy(System.IO.Stream,System.IO.Stream,System.Byte[],ICSharpCode.SharpZipLib.Core.ProgressHandler,System.TimeSpan,System.Object,System.String) + + + + + + + + + + + 100664359 + System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::Copy(System.IO.Stream,System.IO.Stream,System.Byte[],ICSharpCode.SharpZipLib.Core.ProgressHandler,System.TimeSpan,System.Object,System.String,System.Int64) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664360 + System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::.ctor() + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Core.WindowsPathUtils + + + + 100664361 + System.Void ICSharpCode.SharpZipLib.Core.WindowsPathUtils::.ctor() + + + + + + + + + + + 100664362 + System.String ICSharpCode.SharpZipLib.Core.WindowsPathUtils::DropPathRoot(System.String) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Checksum.Adler32 + + + + 100664365 + System.Int64 ICSharpCode.SharpZipLib.Checksum.Adler32::get_Value() + + + + + + + + + + 100664363 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::.ctor() + + + + + + + + + + + + 100664364 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::Reset() + + + + + + + + + + + 100664366 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::Update(System.Int32) + + + + + + + + + + + + + + + 100664367 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::Update(System.Byte[]) + + + + + + + + + + + + + + + + 100664368 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::Update(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664369 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::.cctor() + + + + + + + + + + + + ICSharpCode.SharpZipLib.Checksum.Crc32 + + + + 100664373 + System.Int64 ICSharpCode.SharpZipLib.Checksum.Crc32::get_Value() + + + + + + + + + + 100664370 + System.UInt32 ICSharpCode.SharpZipLib.Checksum.Crc32::ComputeCrc32(System.UInt32,System.Byte) + + + + + + + + + + 100664371 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::.ctor() + + + + + + + + + + + + 100664372 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::Reset() + + + + + + + + + + + 100664374 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::Update(System.Int32) + + + + + + + + + + + 100664375 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::Update(System.Byte[]) + + + + + + + + + + + + + + + + 100664376 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::Update(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664377 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::.cctor() + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.Checksum.BZip2Crc + + + + 100664385 + System.Int64 ICSharpCode.SharpZipLib.Checksum.BZip2Crc::get_Value() + + + + + + + + + + 100664383 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::.ctor() + + + + + + + + + + + + 100664384 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::Reset() + + + + + + + + + + + 100664386 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::Update(System.Int32) + + + + + + + + + + + 100664387 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::Update(System.Byte[]) + + + + + + + + + + + + + + + + 100664388 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::Update(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664389 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::.cctor() + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.BZip2.BZip2 + + + + 100664390 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2::Decompress(System.IO.Stream,System.IO.Stream,System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + 100664391 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2::Compress(System.IO.Stream,System.IO.Stream,System.Boolean,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.BZip2.BZip2Constants + + + + 100664392 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Constants::.ctor() + + + + + + + + + + + 100664393 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Constants::.cctor() + + + + + + + + + + + + ICSharpCode.SharpZipLib.BZip2.BZip2Exception + + + + 100664394 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Exception::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) + + + + + + + + + + + 100664395 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Exception::.ctor() + + + + + + + + + + + 100664396 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Exception::.ctor(System.String) + + + + + + + + + + + 100664397 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Exception::.ctor(System.String,System.Exception) + + + + + + + + + + + + + ICSharpCode.SharpZipLib.BZip2.BZip2InputStream + + + + 100664399 + System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_IsStreamOwner() + + + + + + + + + + 100664400 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100664401 + System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_CanRead() + + + + + + + + + + 100664402 + System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_CanSeek() + + + + + + + + + + 100664403 + System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_CanWrite() + + + + + + + + + + 100664404 + System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_Length() + + + + + + + + + + 100664405 + System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_Position() + + + + + + + + + + 100664406 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::set_Position(System.Int64) + + + + + + + + + + 100664398 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::.ctor(System.IO.Stream) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664407 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Flush() + + + + + + + + + + + + + + + 100664408 + System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + 100664409 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetLength(System.Int64) + + + + + + + + + + 100664410 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100664411 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::WriteByte(System.Byte) + + + + + + + + + + 100664412 + System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + 100664413 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Close() + + + + + + + + + + + + + + + + + 100664414 + System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::ReadByte() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664415 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::MakeMaps() + + + + + + + + + + + + + + + + + + + + + + + 100664416 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Initialize() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664417 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::InitBlock() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664418 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::EndBlock() + + + + + + + + + + + + + + + + + + 100664419 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Complete() + + + + + + + + + + + + + + + + + 100664420 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsSetStream(System.IO.Stream) + + + + + + + + + + + + + 100664421 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::FillBuffer() + + + + + + + + + + + + + + + + + + + + + + + 100664422 + System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsR(System.Int32) + + + + + + + + + + + + + + + + + 100664423 + System.Char ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsGetUChar() + + + + + + + + + + 100664424 + System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsGetIntVS(System.Int32) + + + + + + + + + + 100664425 + System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsGetInt32() + + + + + + + + + + + + + + 100664426 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::RecvDecodingTables() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664427 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::GetAndMoveToFrontDecode() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664428 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupBlock() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664429 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupRandPartA() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664430 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupNoRandPartA() + + + + + + + + + + + + + + + + + + + + + + + + + 100664431 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupRandPartB() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664432 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupRandPartC() + + + + + + + + + + + + + + + + + + + + + + 100664433 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupNoRandPartB() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664434 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupNoRandPartC() + + + + + + + + + + + + + + + + + + + + + + 100664435 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetDecompressStructureSizes(System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664436 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::CompressedStreamEOF() + + + + + + + + + + 100664437 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BlockOverrun() + + + + + + + + + + 100664438 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BadBlockHeader() + + + + + + + + + + 100664439 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::CrcError() + + + + + + + + + + 100664440 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::HbCreateDecodeTables(System.Int32[],System.Int32[],System.Int32[],System.Char[],System.Int32,System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream + + + + 100664444 + System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_IsStreamOwner() + + + + + + + + + + 100664445 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::set_IsStreamOwner(System.Boolean) + + + + + + + + + + + 100664446 + System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_CanRead() + + + + + + + + + + 100664447 + System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_CanSeek() + + + + + + + + + + 100664448 + System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_CanWrite() + + + + + + + + + + 100664449 + System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_Length() + + + + + + + + + + 100664450 + System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_Position() + + + + + + + + + + 100664451 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::set_Position(System.Int64) + + + + + + + + + + 100664461 + System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_BytesWritten() + + + + + + + + + + 100664441 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::.ctor(System.IO.Stream) + + + + + + + + + + + 100664442 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::.ctor(System.IO.Stream,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664443 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Finalize() + + + + + + + + + + + + 100664452 + System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Seek(System.Int64,System.IO.SeekOrigin) + + + + + + + + + + 100664453 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::SetLength(System.Int64) + + + + + + + + + + 100664454 + System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::ReadByte() + + + + + + + + + + 100664455 + System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Read(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + 100664456 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Write(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664457 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::WriteByte(System.Byte) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664458 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Close() + + + + + + + + + + + + 100664459 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::MakeMaps() + + + + + + + + + + + + + + + + + + + + + + + 100664460 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::WriteRun() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664462 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Dispose(System.Boolean) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664463 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Flush() + + + + + + + + + + + 100664464 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Initialize() + + + + + + + + + + + + + + + + + 100664465 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::InitBlock() + + + + + + + + + + + + + + + + + + + + 100664466 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::EndBlock() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664467 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::EndCompression() + + + + + + + + + + + + + + + + + + 100664468 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsSetStream(System.IO.Stream) + + + + + + + + + + + + + + 100664469 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsFinishedWithStream() + + + + + + + + + + + + + + + + + + + 100664470 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsW(System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + 100664471 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsPutUChar(System.Int32) + + + + + + + + + + + 100664472 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsPutint(System.Int32) + + + + + + + + + + + + + + 100664473 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsPutIntVS(System.Int32,System.Int32) + + + + + + + + + + + 100664474 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::SendMTFValues() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664475 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::MoveToFrontCodeAndSend() + + + + + + + + + + + + + 100664476 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::SimpleSort(System.Int32,System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664477 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Vswap(System.Int32,System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + 100664478 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::QSort3(System.Int32,System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664479 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::MainSort() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664480 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::RandomiseBlock() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664481 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::DoReversibleTransformation() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664482 + System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::FullGtU(System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664483 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::AllocateCompressStructures() + + + + + + + + + + + + + + + + + + + + + + + + 100664484 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::GenerateMTFValues() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664485 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Panic() + + + + + + + + + + 100664486 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::HbMakeCodeLengths(System.Char[],System.Int32[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664487 + System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::HbAssignCodes(System.Int32[],System.Char[],System.Int32,System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664488 + System.Byte ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Med3(System.Byte,System.Byte,System.Byte) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <PrivateImplementationDetails> + + + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll + 2015-10-30T07:19:34.0182785Z + System.Core + + + + C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll + 2016-01-23T02:45:41.3556585Z + System.Xml + + + + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_Adler32.htm b/docs/opencover/ICSharpCode.SharpZipLib_Adler32.htm new file mode 100644 index 000000000..f7f340d3f --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_Adler32.htm @@ -0,0 +1,222 @@ + + + + +ICSharpCode.SharpZipLib.Checksum.Adler32 - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Checksum.Adler32
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Checksum\Adler32.cs
Covered lines:35
Uncovered lines:6
Coverable lines:41
Total lines:175
Line coverage:85.3%
Branch coverage:100%
+

Metrics

+ + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
Reset()1100100
Update(...)100
Update(...)2100100
Update(...)9100100
.cctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Checksum\Adler32.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Checksum
 4{
 5  /// <summary>
 6  /// Computes Adler32 checksum for a stream of data. An Adler32
 7  /// checksum is not as reliable as a CRC32 checksum, but a lot faster to
 8  /// compute.
 9  ///
 10  /// The specification for Adler32 may be found in RFC 1950.
 11  /// ZLIB Compressed Data Format Specification version 3.3)
 12  ///
 13  ///
 14  /// From that document:
 15  ///
 16  ///      "ADLER32 (Adler-32 checksum)
 17  ///       This contains a checksum value of the uncompressed data
 18  ///       (excluding any dictionary data) computed according to Adler-32
 19  ///       algorithm. This algorithm is a 32-bit extension and improvement
 20  ///       of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
 21  ///       standard.
 22  ///
 23  ///       Adler-32 is composed of two sums accumulated per byte: s1 is
 24  ///       the sum of all bytes, s2 is the sum of all s1 values. Both sums
 25  ///       are done modulo 65521. s1 is initialized to 1, s2 to zero.  The
 26  ///       Adler-32 checksum is stored as s2*65536 + s1 in most-
 27  ///       significant-byte first (network) order."
 28  ///
 29  ///  "8.2. The Adler-32 algorithm
 30  ///
 31  ///    The Adler-32 algorithm is much faster than the CRC32 algorithm yet
 32  ///    still provides an extremely low probability of undetected errors.
 33  ///
 34  ///    The modulo on unsigned long accumulators can be delayed for 5552
 35  ///    bytes, so the modulo operation time is negligible.  If the bytes
 36  ///    are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
 37  ///    and order sensitive, unlike the first sum, which is just a
 38  ///    checksum.  That 65521 is prime is important to avoid a possible
 39  ///    large class of two-byte errors that leave the check unchanged.
 40  ///    (The Fletcher checksum uses 255, which is not prime and which also
 41  ///    makes the Fletcher check insensitive to single byte changes 0 -
 42  ///    255.)
 43  ///
 44  ///    The sum s1 is initialized to 1 instead of zero to make the length
 45  ///    of the sequence part of s2, so that the length does not have to be
 46  ///    checked separately. (Any sequence of zeroes has a Fletcher
 47  ///    checksum of zero.)"
 48  /// </summary>
 49  /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream"/>
 50  /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream"/>
 51  public sealed class Adler32 : IChecksum
 52  {
 53    #region Instance Fields
 54    /// <summary>
 55    /// largest prime smaller than 65536
 56    /// </summary>
 157    readonly static uint BASE = 65521;
 58
 59    /// <summary>
 60    /// The CRC data checksum so far.
 61    /// </summary>
 62    uint checkValue;
 63    #endregion
 64
 65    /// <summary>
 66    /// Initialise a default instance of <see cref="Adler32"></see>
 67    /// </summary>
 70968    public Adler32()
 69    {
 70970      Reset();
 70971    }
 72
 73    /// <summary>
 74    /// Resets the Adler32 data checksum as if no update was ever called.
 75    /// </summary>
 76    public void Reset()
 77    {
 114378      checkValue = 1;
 114379    }
 80
 81    /// <summary>
 82    /// Returns the Adler32 data checksum computed so far.
 83    /// </summary>
 84    public long Value {
 85      get {
 1886        return checkValue;
 87      }
 88    }
 89
 90    /// <summary>
 91    /// Updates the checksum with the byte b.
 92    /// </summary>
 93    /// <param name="bval">
 94    /// The data value to add. The high byte of the int is ignored.
 95    /// </param>
 96    public void Update(int bval)
 97    {
 98      // We could make a length 1 byte array and call update again, but I
 99      // would rather not have that overhead
 0100      uint s1 = checkValue & 0xFFFF;
 0101      uint s2 = checkValue >> 16;
 102
 0103      s1 = (s1 + ((uint)bval & 0xFF)) % BASE;
 0104      s2 = (s1 + s2) % BASE;
 105
 0106      checkValue = (s2 << 16) + s1;
 0107    }
 108
 109    /// <summary>
 110    /// Updates the Adler32 data checksum with the bytes taken from
 111    /// a block of data.
 112    /// </summary>
 113    /// <param name="buffer">Contains the data to update the checksum with.</param>
 114    public void Update(byte[] buffer)
 115    {
 2116       if (buffer == null) {
 1117        throw new ArgumentNullException(nameof(buffer));
 118      }
 119
 1120      Update(buffer, 0, buffer.Length);
 1121    }
 122
 123    /// <summary>
 124    /// Update Adler32 data checksum based on a portion of a block of data
 125    /// </summary>
 126    /// <param name = "buffer">Contains the data to update the CRC with.</param>
 127    /// <param name = "offset">The offset into the buffer where the data starts</param>
 128    /// <param name = "count">The number of data bytes to update the CRC with.</param>
 129    public void Update(byte[] buffer, int offset, int count)
 130    {
 6204131       if (buffer == null) {
 1132        throw new ArgumentNullException(nameof(buffer));
 133      }
 134
 6203135       if (offset < 0) {
 1136        throw new ArgumentOutOfRangeException(nameof(offset), "cannot be less than zero");
 137      }
 138
 6202139       if (offset >= buffer.Length) {
 1140        throw new ArgumentOutOfRangeException(nameof(offset), "not a valid index into buffer");
 141      }
 142
 6201143       if (count < 0) {
 1144        throw new ArgumentOutOfRangeException(nameof(count), "cannot be less than zero");
 145      }
 146
 6200147       if (offset + count > buffer.Length) {
 1148        throw new ArgumentOutOfRangeException(nameof(count), "exceeds buffer size");
 149      }
 150
 151      //(By Per Bothner)
 6199152      uint s1 = checkValue & 0xFFFF;
 6199153      uint s2 = checkValue >> 16;
 154
 13890155       while (count > 0) {
 156        // We can defer the modulo operation:
 157        // s1 maximally grows from 65521 to 65521 + 255 * 3800
 158        // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
 7691159        int n = 3800;
 7691160         if (n > count) {
 6199161          n = count;
 162        }
 7691163        count -= n;
 8355525164         while (--n >= 0) {
 8347834165          s1 = s1 + (uint)(buffer[offset++] & 0xff);
 8347834166          s2 = s2 + s1;
 167        }
 7691168        s1 %= BASE;
 7691169        s2 %= BASE;
 170      }
 171
 6199172      checkValue = (s2 << 16) | s1;
 6199173    }
 174  }
 175}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_BZip2.htm b/docs/opencover/ICSharpCode.SharpZipLib_BZip2.htm new file mode 100644 index 000000000..80405d917 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_BZip2.htm @@ -0,0 +1,109 @@ + + + + +ICSharpCode.SharpZipLib.BZip2.BZip2 - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.BZip2.BZip2
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2.cs
Covered lines:0
Uncovered lines:20
Coverable lines:20
Total lines:66
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
Decompress(...)500
Compress(...)500
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.BZip2
 5{
 6  /// <summary>
 7  /// An example class to demonstrate compression and decompression of BZip2 streams.
 8  /// </summary>
 9  public static class BZip2
 10  {
 11    /// <summary>
 12    /// Decompress the <paramref name="inStream">input</paramref> writing
 13    /// uncompressed data to the <paramref name="outStream">output stream</paramref>
 14    /// </summary>
 15    /// <param name="inStream">The readable stream containing data to decompress.</param>
 16    /// <param name="outStream">The output stream to receive the decompressed data.</param>
 17    /// <param name="isStreamOwner">Both streams are closed on completion if true.</param>
 18    public static void Decompress(Stream inStream, Stream outStream, bool isStreamOwner)
 19    {
 020       if (inStream == null || outStream == null) {
 021        throw new Exception("Null Stream");
 22      }
 23
 24      try {
 025        using (BZip2InputStream bzipInput = new BZip2InputStream(inStream)) {
 026          bzipInput.IsStreamOwner = isStreamOwner;
 027          Core.StreamUtils.Copy(bzipInput, outStream, new byte[4096]);
 028        }
 29      } finally {
 030         if (isStreamOwner) {
 31          // inStream is closed by the BZip2InputStream if stream owner
 032          outStream.Close();
 33        }
 034      }
 035    }
 36
 37    /// <summary>
 38    /// Compress the <paramref name="inStream">input stream</paramref> sending
 39    /// result data to <paramref name="outStream">output stream</paramref>
 40    /// </summary>
 41    /// <param name="inStream">The readable stream to compress.</param>
 42    /// <param name="outStream">The output stream to receive the compressed data.</param>
 43    /// <param name="isStreamOwner">Both streams are closed on completion if true.</param>
 44    /// <param name="level">Block size acts as compression level (1 to 9) with 1 giving
 45    /// the lowest compression and 9 the highest.</param>
 46    public static void Compress(Stream inStream, Stream outStream, bool isStreamOwner, int level)
 47    {
 048       if (inStream == null || outStream == null) {
 049        throw new Exception("Null Stream");
 50      }
 51
 52      try {
 053        using (BZip2OutputStream bzipOutput = new BZip2OutputStream(outStream, level)) {
 054          bzipOutput.IsStreamOwner = isStreamOwner;
 055          Core.StreamUtils.Copy(inStream, bzipOutput, new byte[4096]);
 056        }
 57      } finally {
 058         if (isStreamOwner) {
 59          // outStream is closed by the BZip2OutputStream if stream owner
 060          inStream.Close();
 61        }
 062      }
 063    }
 64
 65  }
 66}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_BZip2Constants.htm b/docs/opencover/ICSharpCode.SharpZipLib_BZip2Constants.htm new file mode 100644 index 000000000..b07f50436 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_BZip2Constants.htm @@ -0,0 +1,163 @@ + + + + +ICSharpCode.SharpZipLib.BZip2.BZip2Constants - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.BZip2.BZip2Constants
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2Constants.cs
Covered lines:0
Uncovered lines:56
Coverable lines:56
Total lines:121
Line coverage:0%
+

Metrics

+ + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()100
.cctor()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2Constants.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1namespace ICSharpCode.SharpZipLib.BZip2
 2{
 3  /// <summary>
 4  /// Defines internal values for both compression and decompression
 5  /// </summary>
 6  internal sealed class BZip2Constants
 7  {
 8    /// <summary>
 9    /// Random numbers used to randomise repetitive blocks
 10    /// </summary>
 011    public readonly static int[] RandomNumbers = {
 012      619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
 013      985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
 014      733, 859, 335, 708, 621, 574,  73, 654, 730, 472,
 015      419, 436, 278, 496, 867, 210, 399, 680, 480,  51,
 016      878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
 017      862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
 018      150, 238,  59, 379, 684, 877, 625, 169, 643, 105,
 019      170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
 020       73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
 021      909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
 022      641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
 023      161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
 024      382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
 025       98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
 026      227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
 027      469,  68, 770, 919, 190, 373, 294, 822, 808, 206,
 028      184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
 029      715,  67, 618, 276, 204, 918, 873, 777, 604, 560,
 030      951, 160, 578, 722,  79, 804,  96, 409, 713, 940,
 031      652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
 032      645, 863, 803, 350, 139,  93, 354,  99, 820, 908,
 033      609, 772, 154, 274, 580, 184,  79, 626, 630, 742,
 034      653, 282, 762, 623, 680,  81, 927, 626, 789, 125,
 035      411, 521, 938, 300, 821,  78, 343, 175, 128, 250,
 036      170, 774, 972, 275, 999, 639, 495,  78, 352, 126,
 037      857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
 038      669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
 039      944, 375, 748,  52, 600, 747, 642, 182, 862,  81,
 040      344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
 041      897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
 042      433, 837, 553, 268, 926, 240, 102, 654, 459,  51,
 043      686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
 044      946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
 045      978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
 046      680, 879, 194, 572, 640, 724, 926,  56, 204, 700,
 047      707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
 048      297,  59,  87, 824, 713, 663, 412, 693, 342, 606,
 049      134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
 050      343,  97, 430, 751, 497, 314, 983, 374, 822, 928,
 051      140, 206,  73, 263, 980, 736, 876, 478, 430, 305,
 052      170, 514, 364, 692, 829,  82, 855, 953, 676, 246,
 053      369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
 054      804, 378, 215, 828, 592, 281, 565, 555, 710,  82,
 055      896, 831, 547, 261, 524, 462, 293, 465, 502,  56,
 056      661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
 057      768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
 058       61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
 059      372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
 060      780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
 061      920, 176, 193, 713, 857, 265, 203,  50, 668, 108,
 062      645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
 063      936, 638
 064    };
 65
 66    /// <summary>
 67    /// When multiplied by compression parameter (1-9) gives the block size for compression
 68    /// 9 gives the best compression but uses the most memory.
 69    /// </summary>
 70    public const int BaseBlockSize = 100000;
 71
 72    /// <summary>
 73    /// Backend constant
 74    /// </summary>
 75    public const int MaximumAlphaSize = 258;
 76
 77    /// <summary>
 78    /// Backend constant
 79    /// </summary>
 80    public const int MaximumCodeLength = 23;
 81
 82    /// <summary>
 83    /// Backend constant
 84    /// </summary>
 85    public const int RunA = 0;
 86
 87    /// <summary>
 88    /// Backend constant
 89    /// </summary>
 90    public const int RunB = 1;
 91
 92    /// <summary>
 93    /// Backend constant
 94    /// </summary>
 95    public const int GroupCount = 6;
 96
 97    /// <summary>
 98    /// Backend constant
 99    /// </summary>
 100    public const int GroupSize = 50;
 101
 102    /// <summary>
 103    /// Backend constant
 104    /// </summary>
 105    public const int NumberOfIterations = 4;
 106
 107    /// <summary>
 108    /// Backend constant
 109    /// </summary>
 110    public const int MaximumSelectors = (2 + (900000 / GroupSize));
 111
 112    /// <summary>
 113    /// Backend constant
 114    /// </summary>
 115    public const int OvershootBytes = 20;
 116
 0117    private BZip2Constants()
 118    {
 0119    }
 120  }
 121}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_BZip2Crc.htm b/docs/opencover/ICSharpCode.SharpZipLib_BZip2Crc.htm new file mode 100644 index 000000000..5777ac373 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_BZip2Crc.htm @@ -0,0 +1,247 @@ + + + + +ICSharpCode.SharpZipLib.Checksum.BZip2Crc - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Checksum.BZip2Crc
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Checksum\BZip2Crc.cs
Covered lines:93
Uncovered lines:0
Coverable lines:93
Total lines:200
Line coverage:100%
Branch coverage:100%
+

Metrics

+ + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
Reset()1100100
Update(...)1100100
Update(...)2100100
Update(...)7100100
.cctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Checksum\BZip2Crc.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Checksum
 4{
 5  /// <summary>
 6  /// CRC-32 with unreversed data and reversed output
 7  /// </summary>
 8  /// <remarks>
 9  /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
 10  /// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0.
 11  ///
 12  /// Polynomials over GF(2) are represented in binary, one bit per coefficient,
 13  /// with the lowest powers in the most significant bit.  Then adding polynomials
 14  /// is just exclusive-or, and multiplying a polynomial by x is a right shift by
 15  /// one.  If we call the above polynomial p, and represent a byte as the
 16  /// polynomial q, also with the lowest power in the most significant bit (so the
 17  /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
 18  /// where a mod b means the remainder after dividing a by b.
 19  ///
 20  /// This calculation is done using the shift-register method of multiplying and
 21  /// taking the remainder.  The register is initialized to zero, and for each
 22  /// incoming bit, x^32 is added mod p to the register if the bit is a one (where
 23  /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
 24  /// x (which is shifting right by one and adding x^32 mod p if the bit shifted
 25  /// out is a one).  We start with the highest power (least significant bit) of
 26  /// q and repeat for all eight bits of q.
 27  ///
 28  /// The table is simply the CRC of all possible eight bit values.  This is all
 29  /// the information needed to generate CRC's on data a byte at a time for all
 30  /// combinations of CRC register values and incoming bytes.
 31  /// </remarks>
 32  public sealed class BZip2Crc : IChecksum
 33  {
 34    #region Instance Fields
 135    readonly static uint crcInit = 0xFFFFFFFF;
 136    readonly static uint crcXor = 0x00000000;
 37
 138    readonly static uint[] crcTable = {
 139      0X00000000, 0X04C11DB7, 0X09823B6E, 0X0D4326D9,
 140      0X130476DC, 0X17C56B6B, 0X1A864DB2, 0X1E475005,
 141      0X2608EDB8, 0X22C9F00F, 0X2F8AD6D6, 0X2B4BCB61,
 142      0X350C9B64, 0X31CD86D3, 0X3C8EA00A, 0X384FBDBD,
 143      0X4C11DB70, 0X48D0C6C7, 0X4593E01E, 0X4152FDA9,
 144      0X5F15ADAC, 0X5BD4B01B, 0X569796C2, 0X52568B75,
 145      0X6A1936C8, 0X6ED82B7F, 0X639B0DA6, 0X675A1011,
 146      0X791D4014, 0X7DDC5DA3, 0X709F7B7A, 0X745E66CD,
 147      0X9823B6E0, 0X9CE2AB57, 0X91A18D8E, 0X95609039,
 148      0X8B27C03C, 0X8FE6DD8B, 0X82A5FB52, 0X8664E6E5,
 149      0XBE2B5B58, 0XBAEA46EF, 0XB7A96036, 0XB3687D81,
 150      0XAD2F2D84, 0XA9EE3033, 0XA4AD16EA, 0XA06C0B5D,
 151      0XD4326D90, 0XD0F37027, 0XDDB056FE, 0XD9714B49,
 152      0XC7361B4C, 0XC3F706FB, 0XCEB42022, 0XCA753D95,
 153      0XF23A8028, 0XF6FB9D9F, 0XFBB8BB46, 0XFF79A6F1,
 154      0XE13EF6F4, 0XE5FFEB43, 0XE8BCCD9A, 0XEC7DD02D,
 155      0X34867077, 0X30476DC0, 0X3D044B19, 0X39C556AE,
 156      0X278206AB, 0X23431B1C, 0X2E003DC5, 0X2AC12072,
 157      0X128E9DCF, 0X164F8078, 0X1B0CA6A1, 0X1FCDBB16,
 158      0X018AEB13, 0X054BF6A4, 0X0808D07D, 0X0CC9CDCA,
 159      0X7897AB07, 0X7C56B6B0, 0X71159069, 0X75D48DDE,
 160      0X6B93DDDB, 0X6F52C06C, 0X6211E6B5, 0X66D0FB02,
 161      0X5E9F46BF, 0X5A5E5B08, 0X571D7DD1, 0X53DC6066,
 162      0X4D9B3063, 0X495A2DD4, 0X44190B0D, 0X40D816BA,
 163      0XACA5C697, 0XA864DB20, 0XA527FDF9, 0XA1E6E04E,
 164      0XBFA1B04B, 0XBB60ADFC, 0XB6238B25, 0XB2E29692,
 165      0X8AAD2B2F, 0X8E6C3698, 0X832F1041, 0X87EE0DF6,
 166      0X99A95DF3, 0X9D684044, 0X902B669D, 0X94EA7B2A,
 167      0XE0B41DE7, 0XE4750050, 0XE9362689, 0XEDF73B3E,
 168      0XF3B06B3B, 0XF771768C, 0XFA325055, 0XFEF34DE2,
 169      0XC6BCF05F, 0XC27DEDE8, 0XCF3ECB31, 0XCBFFD686,
 170      0XD5B88683, 0XD1799B34, 0XDC3ABDED, 0XD8FBA05A,
 171      0X690CE0EE, 0X6DCDFD59, 0X608EDB80, 0X644FC637,
 172      0X7A089632, 0X7EC98B85, 0X738AAD5C, 0X774BB0EB,
 173      0X4F040D56, 0X4BC510E1, 0X46863638, 0X42472B8F,
 174      0X5C007B8A, 0X58C1663D, 0X558240E4, 0X51435D53,
 175      0X251D3B9E, 0X21DC2629, 0X2C9F00F0, 0X285E1D47,
 176      0X36194D42, 0X32D850F5, 0X3F9B762C, 0X3B5A6B9B,
 177      0X0315D626, 0X07D4CB91, 0X0A97ED48, 0X0E56F0FF,
 178      0X1011A0FA, 0X14D0BD4D, 0X19939B94, 0X1D528623,
 179      0XF12F560E, 0XF5EE4BB9, 0XF8AD6D60, 0XFC6C70D7,
 180      0XE22B20D2, 0XE6EA3D65, 0XEBA91BBC, 0XEF68060B,
 181      0XD727BBB6, 0XD3E6A601, 0XDEA580D8, 0XDA649D6F,
 182      0XC423CD6A, 0XC0E2D0DD, 0XCDA1F604, 0XC960EBB3,
 183      0XBD3E8D7E, 0XB9FF90C9, 0XB4BCB610, 0XB07DABA7,
 184      0XAE3AFBA2, 0XAAFBE615, 0XA7B8C0CC, 0XA379DD7B,
 185      0X9B3660C6, 0X9FF77D71, 0X92B45BA8, 0X9675461F,
 186      0X8832161A, 0X8CF30BAD, 0X81B02D74, 0X857130C3,
 187      0X5D8A9099, 0X594B8D2E, 0X5408ABF7, 0X50C9B640,
 188      0X4E8EE645, 0X4A4FFBF2, 0X470CDD2B, 0X43CDC09C,
 189      0X7B827D21, 0X7F436096, 0X7200464F, 0X76C15BF8,
 190      0X68860BFD, 0X6C47164A, 0X61043093, 0X65C52D24,
 191      0X119B4BE9, 0X155A565E, 0X18197087, 0X1CD86D30,
 192      0X029F3D35, 0X065E2082, 0X0B1D065B, 0X0FDC1BEC,
 193      0X3793A651, 0X3352BBE6, 0X3E119D3F, 0X3AD08088,
 194      0X2497D08D, 0X2056CD3A, 0X2D15EBE3, 0X29D4F654,
 195      0XC5A92679, 0XC1683BCE, 0XCC2B1D17, 0XC8EA00A0,
 196      0XD6AD50A5, 0XD26C4D12, 0XDF2F6BCB, 0XDBEE767C,
 197      0XE3A1CBC1, 0XE760D676, 0XEA23F0AF, 0XEEE2ED18,
 198      0XF0A5BD1D, 0XF464A0AA, 0XF9278673, 0XFDE69BC4,
 199      0X89B8FD09, 0X8D79E0BE, 0X803AC667, 0X84FBDBD0,
 1100      0X9ABC8BD5, 0X9E7D9662, 0X933EB0BB, 0X97FFAD0C,
 1101      0XAFB010B1, 0XAB710D06, 0XA6322BDF, 0XA2F33668,
 1102      0XBCB4666D, 0XB8757BDA, 0XB5365D03, 0XB1F740B4
 1103    };
 104
 105    /// <summary>
 106    /// The CRC data checksum so far.
 107    /// </summary>
 108    uint checkValue;
 109    #endregion
 110
 111    /// <summary>
 112    /// Initialise a default instance of <see cref="BZip2Crc"></see>
 113    /// </summary>
 3114    public BZip2Crc()
 115    {
 3116      Reset();
 3117    }
 118
 119    /// <summary>
 120    /// Resets the CRC data checksum as if no update was ever called.
 121    /// </summary>
 122    public void Reset()
 123    {
 5124      checkValue = crcInit;
 5125    }
 126
 127    /// <summary>
 128    /// Returns the CRC data checksum computed so far.
 129    /// </summary>
 130    /// <remarks>Reversed Out = true</remarks>
 131    public long Value {
 132      get {
 133        // Tehcnically, the output should be:
 134        //return (long)(~checkValue ^ crcXor);
 135        // but x ^ 0 = x, so there is no point in adding
 136        // the XOR operation
 3137        return (long)(~checkValue);
 138      }
 139    }
 140
 141    /// <summary>
 142    /// Updates the checksum with the int bval.
 143    /// </summary>
 144    /// <param name = "bval">
 145    /// the byte is taken as the lower 8 bits of bval
 146    /// </param>
 147    /// <remarks>Reversed Data = false</remarks>
 148    public void Update(int bval)
 149    {
 10150      checkValue = unchecked(crcTable[(byte)(((checkValue >> 24) & 0xFF) ^ bval)] ^ (checkValue << 8));
 10151    }
 152
 153    /// <summary>
 154    /// Updates the CRC data checksum with the bytes taken from
 155    /// a block of data.
 156    /// </summary>
 157    /// <param name="buffer">Contains the data to update the CRC with.</param>
 158    public void Update(byte[] buffer)
 159    {
 2160       if (buffer == null) {
 1161        throw new ArgumentNullException(nameof(buffer));
 162      }
 163
 1164      Update(buffer, 0, buffer.Length);
 1165    }
 166
 167    /// <summary>
 168    /// Update CRC data checksum based on a portion of a block of data
 169    /// </summary>
 170    /// <param name = "buffer">Contains the data to update the CRC with.</param>
 171    /// <param name = "offset">The offset into the buffer where the data starts</param>
 172    /// <param name = "count">The number of data bytes to update the CRC with.</param>
 173    public void Update(byte[] buffer, int offset, int count)
 174    {
 6175       if (buffer == null) {
 1176        throw new ArgumentNullException(nameof(buffer));
 177      }
 178
 5179       if (offset < 0) {
 1180        throw new ArgumentOutOfRangeException(nameof(offset), "cannot be less than zero");
 181      }
 182
 4183       if (offset >= buffer.Length) {
 1184        throw new ArgumentOutOfRangeException(nameof(offset), "not a valid index into buffer");
 185      }
 186
 3187       if (count < 0) {
 1188        throw new ArgumentOutOfRangeException(nameof(count), "cannot be less than zero");
 189      }
 190
 2191       if (offset + count > buffer.Length) {
 1192        throw new ArgumentOutOfRangeException(nameof(count), "exceeds buffer size");
 193      }
 194
 20195       for (int i = 0; i < count; ++i) {
 9196        Update(buffer[offset++]);
 197      }
 1198    }
 199  }
 200}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_BZip2Exception.htm b/docs/opencover/ICSharpCode.SharpZipLib_BZip2Exception.htm new file mode 100644 index 000000000..878f863cd --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_BZip2Exception.htm @@ -0,0 +1,92 @@ + + + + +ICSharpCode.SharpZipLib.BZip2.BZip2Exception - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.BZip2.BZip2Exception
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2Exception.cs
Covered lines:0
Uncovered lines:8
Coverable lines:8
Total lines:48
Line coverage:0%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor()100
.ctor(...)100
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2Exception.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Runtime.Serialization;
 3
 4namespace ICSharpCode.SharpZipLib.BZip2
 5{
 6  /// <summary>
 7  /// BZip2Exception represents exceptions specific to BZip2 classes and code.
 8  /// </summary>
 9  [Serializable]
 10  public class BZip2Exception : SharpZipBaseException
 11  {
 12    /// <summary>
 13    /// Deserialization constructor
 14    /// </summary>
 15    /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
 16    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
 17    protected BZip2Exception(SerializationInfo info, StreamingContext context)
 018      : base(info, context)
 19    {
 020    }
 21
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="BZip2Exception" />.
 24    /// </summary>
 025    public BZip2Exception()
 26    {
 027    }
 28
 29    /// <summary>
 30    /// Initialise a new instance of <see cref="BZip2Exception" /> with its message string.
 31    /// </summary>
 32    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 33    public BZip2Exception(string message)
 034      : base(message)
 35    {
 036    }
 37
 38    /// <summary>
 39    /// Initialise a new instance of <see cref="BZip2Exception" />.
 40    /// </summary>
 41    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 42    /// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
 43    public BZip2Exception(string message, Exception innerException)
 044      : base(message, innerException)
 45    {
 046    }
 47  }
 48}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_BZip2InputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_BZip2InputStream.htm new file mode 100644 index 000000000..b20003e80 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_BZip2InputStream.htm @@ -0,0 +1,985 @@ + + + + +ICSharpCode.SharpZipLib.BZip2.BZip2InputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.BZip2.BZip2InputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2InputStream.cs
Covered lines:111
Uncovered lines:315
Coverable lines:426
Total lines:909
Line coverage:26%
Branch coverage:15.7%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)2100100
Flush()200
Seek(...)100
SetLength(...)100
Write(...)100
WriteByte(...)100
Read(...)46057.14
Close()310060
ReadByte()716.6718.18
MakeMaps()300
Initialize()68054.55
InitBlock()1347.3728
EndBlock()200
Complete()28066.67
BsSetStream(...)1100100
FillBuffer()263.6466.67
BsR(...)2100100
BsGetUChar()1100100
BsGetIntVS(...)100
BsGetInt32()1100100
RecvDecodingTables()1800
GetAndMoveToFrontDecode()2600
SetupBlock()48485.71
SetupRandPartA()600
SetupNoRandPartA()269.2366.67
SetupRandPartB()700
SetupRandPartC()200
SetupNoRandPartB()300
SetupNoRandPartC()200
SetDecompressStructureSizes(...)677.7854.55
CompressedStreamEOF()100
BlockOverrun()100
BadBlockHeader()100
CrcError()100
HbCreateDecodeTables(...)1000
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2InputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using ICSharpCode.SharpZipLib.Checksum;
 4
 5namespace ICSharpCode.SharpZipLib.BZip2
 6{
 7  /// <summary>
 8  /// An input stream that decompresses files in the BZip2 format
 9  /// </summary>
 10  public class BZip2InputStream : Stream
 11  {
 12    #region Constants
 13    const int START_BLOCK_STATE = 1;
 14    const int RAND_PART_A_STATE = 2;
 15    const int RAND_PART_B_STATE = 3;
 16    const int RAND_PART_C_STATE = 4;
 17    const int NO_RAND_PART_A_STATE = 5;
 18    const int NO_RAND_PART_B_STATE = 6;
 19    const int NO_RAND_PART_C_STATE = 7;
 20    #endregion
 21    #region Constructors
 22    /// <summary>
 23    /// Construct instance for reading from stream
 24    /// </summary>
 25    /// <param name="stream">Data source</param>
 126    public BZip2InputStream(Stream stream)
 27    {
 28      // init arrays
 1429       for (int i = 0; i < BZip2Constants.GroupCount; ++i) {
 630        limit[i] = new int[BZip2Constants.MaximumAlphaSize];
 631        baseArray[i] = new int[BZip2Constants.MaximumAlphaSize];
 632        perm[i] = new int[BZip2Constants.MaximumAlphaSize];
 33      }
 34
 135      BsSetStream(stream);
 136      Initialize();
 137      InitBlock();
 138      SetupBlock();
 139    }
 40
 41    #endregion
 42
 43    /// <summary>
 44    /// Get/set flag indicating ownership of underlying stream.
 45    /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
 46    /// </summary>
 47    public bool IsStreamOwner {
 148      get { return isStreamOwner; }
 049      set { isStreamOwner = value; }
 50    }
 51
 52
 53    #region Stream Overrides
 54    /// <summary>
 55    /// Gets a value indicating if the stream supports reading
 56    /// </summary>
 57    public override bool CanRead {
 58      get {
 059        return baseStream.CanRead;
 60      }
 61    }
 62
 63    /// <summary>
 64    /// Gets a value indicating whether the current stream supports seeking.
 65    /// </summary>
 66    public override bool CanSeek {
 67      get {
 068        return baseStream.CanSeek;
 69      }
 70    }
 71
 72    /// <summary>
 73    /// Gets a value indicating whether the current stream supports writing.
 74    /// This property always returns false
 75    /// </summary>
 76    public override bool CanWrite {
 77      get {
 078        return false;
 79      }
 80    }
 81
 82    /// <summary>
 83    /// Gets the length in bytes of the stream.
 84    /// </summary>
 85    public override long Length {
 86      get {
 087        return baseStream.Length;
 88      }
 89    }
 90
 91    /// <summary>
 92    /// Gets or sets the streams position.
 93    /// Setting the position is not supported and will throw a NotSupportException
 94    /// </summary>
 95    /// <exception cref="NotSupportedException">Any attempt to set the position</exception>
 96    public override long Position {
 97      get {
 098        return baseStream.Position;
 99      }
 100      set {
 0101        throw new NotSupportedException("BZip2InputStream position cannot be set");
 102      }
 103    }
 104
 105    /// <summary>
 106    /// Flushes the stream.
 107    /// </summary>
 108    public override void Flush()
 109    {
 0110       if (baseStream != null) {
 0111        baseStream.Flush();
 112      }
 0113    }
 114
 115    /// <summary>
 116    /// Set the streams position.  This operation is not supported and will throw a NotSupportedException
 117    /// </summary>
 118    /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>
 119    /// <param name="origin">A value of type <see cref="SeekOrigin"/> indicating the reference point used to obtain the 
 120    /// <returns>The new position of the stream.</returns>
 121    /// <exception cref="NotSupportedException">Any access</exception>
 122    public override long Seek(long offset, SeekOrigin origin)
 123    {
 0124      throw new NotSupportedException("BZip2InputStream Seek not supported");
 125    }
 126
 127    /// <summary>
 128    /// Sets the length of this stream to the given value.
 129    /// This operation is not supported and will throw a NotSupportedExceptionortedException
 130    /// </summary>
 131    /// <param name="value">The new length for the stream.</param>
 132    /// <exception cref="NotSupportedException">Any access</exception>
 133    public override void SetLength(long value)
 134    {
 0135      throw new NotSupportedException("BZip2InputStream SetLength not supported");
 136    }
 137
 138    /// <summary>
 139    /// Writes a block of bytes to this stream using data from a buffer.
 140    /// This operation is not supported and will throw a NotSupportedException
 141    /// </summary>
 142    /// <param name="buffer">The buffer to source data from.</param>
 143    /// <param name="offset">The offset to start obtaining data from.</param>
 144    /// <param name="count">The number of bytes of data to write.</param>
 145    /// <exception cref="NotSupportedException">Any access</exception>
 146    public override void Write(byte[] buffer, int offset, int count)
 147    {
 0148      throw new NotSupportedException("BZip2InputStream Write not supported");
 149    }
 150
 151    /// <summary>
 152    /// Writes a byte to the current position in the file stream.
 153    /// This operation is not supported and will throw a NotSupportedException
 154    /// </summary>
 155    /// <param name="value">The value to write.</param>
 156    /// <exception cref="NotSupportedException">Any access</exception>
 157    public override void WriteByte(byte value)
 158    {
 0159      throw new NotSupportedException("BZip2InputStream WriteByte not supported");
 160    }
 161
 162    /// <summary>
 163    /// Read a sequence of bytes and advances the read position by one byte.
 164    /// </summary>
 165    /// <param name="buffer">Array of bytes to store values in</param>
 166    /// <param name="offset">Offset in array to begin storing data</param>
 167    /// <param name="count">The maximum number of bytes to read</param>
 168    /// <returns>The total number of bytes read into the buffer. This might be less
 169    /// than the number of bytes requested if that number of bytes are not
 170    /// currently available or zero if the end of the stream is reached.
 171    /// </returns>
 172    public override int Read(byte[] buffer, int offset, int count)
 173    {
 1174       if (buffer == null) {
 0175        throw new ArgumentNullException(nameof(buffer));
 176      }
 177
 2178       for (int i = 0; i < count; ++i) {
 1179        int rb = ReadByte();
 1180         if (rb == -1) {
 1181          return i;
 182        }
 0183        buffer[offset + i] = (byte)rb;
 184      }
 0185      return count;
 186    }
 187
 188    /// <summary>
 189    /// Closes the stream, releasing any associated resources.
 190    /// </summary>
 191    public override void Close()
 192    {
 1193       if (IsStreamOwner && (baseStream != null)) {
 1194        baseStream.Close();
 195      }
 1196    }
 197    /// <summary>
 198    /// Read a byte from stream advancing position
 199    /// </summary>
 200    /// <returns>byte read or -1 on end of stream</returns>
 201    public override int ReadByte()
 202    {
 1203       if (streamEnd) {
 1204        return -1; // ok
 205      }
 206
 0207      int retChar = currentChar;
 0208       switch (currentState) {
 209        case RAND_PART_B_STATE:
 0210          SetupRandPartB();
 0211          break;
 212        case RAND_PART_C_STATE:
 0213          SetupRandPartC();
 0214          break;
 215        case NO_RAND_PART_B_STATE:
 0216          SetupNoRandPartB();
 0217          break;
 218        case NO_RAND_PART_C_STATE:
 0219          SetupNoRandPartC();
 220          break;
 221        case START_BLOCK_STATE:
 222        case NO_RAND_PART_A_STATE:
 223        case RAND_PART_A_STATE:
 224          break;
 225      }
 0226      return retChar;
 227    }
 228
 229    #endregion
 230
 231    void MakeMaps()
 232    {
 0233      nInUse = 0;
 0234       for (int i = 0; i < 256; ++i) {
 0235         if (inUse[i]) {
 0236          seqToUnseq[nInUse] = (byte)i;
 0237          unseqToSeq[i] = (byte)nInUse;
 0238          nInUse++;
 239        }
 240      }
 0241    }
 242
 243    void Initialize()
 244    {
 1245      char magic1 = BsGetUChar();
 1246      char magic2 = BsGetUChar();
 247
 1248      char magic3 = BsGetUChar();
 1249      char magic4 = BsGetUChar();
 250
 1251       if (magic1 != 'B' || magic2 != 'Z' || magic3 != 'h' || magic4 < '1' || magic4 > '9') {
 0252        streamEnd = true;
 0253        return;
 254      }
 255
 1256      SetDecompressStructureSizes(magic4 - '0');
 1257      computedCombinedCRC = 0;
 1258    }
 259
 260    void InitBlock()
 261    {
 1262      char magic1 = BsGetUChar();
 1263      char magic2 = BsGetUChar();
 1264      char magic3 = BsGetUChar();
 1265      char magic4 = BsGetUChar();
 1266      char magic5 = BsGetUChar();
 1267      char magic6 = BsGetUChar();
 268
 1269       if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) {
 1270        Complete();
 1271        return;
 272      }
 273
 0274       if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) {
 0275        BadBlockHeader();
 0276        streamEnd = true;
 0277        return;
 278      }
 279
 0280      storedBlockCRC = BsGetInt32();
 281
 0282      blockRandomised = (BsR(1) == 1);
 283
 0284      GetAndMoveToFrontDecode();
 285
 0286      mCrc.Reset();
 0287      currentState = START_BLOCK_STATE;
 0288    }
 289
 290    void EndBlock()
 291    {
 0292      computedBlockCRC = (int)mCrc.Value;
 293
 294      // -- A bad CRC is considered a fatal error. --
 0295       if (storedBlockCRC != computedBlockCRC) {
 0296        CrcError();
 297      }
 298
 299      // 1528150659
 0300      computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFF) | (computedCombinedCRC >> 31);
 0301      computedCombinedCRC = computedCombinedCRC ^ (uint)computedBlockCRC;
 0302    }
 303
 304    void Complete()
 305    {
 1306      storedCombinedCRC = BsGetInt32();
 1307       if (storedCombinedCRC != (int)computedCombinedCRC) {
 0308        CrcError();
 309      }
 310
 1311      streamEnd = true;
 1312    }
 313
 314    void BsSetStream(Stream stream)
 315    {
 1316      baseStream = stream;
 1317      bsLive = 0;
 1318      bsBuff = 0;
 1319    }
 320
 321    void FillBuffer()
 322    {
 14323      int thech = 0;
 324
 325      try {
 14326        thech = baseStream.ReadByte();
 14327      } catch (Exception) {
 0328        CompressedStreamEOF();
 0329      }
 330
 14331       if (thech == -1) {
 0332        CompressedStreamEOF();
 333      }
 334
 14335      bsBuff = (bsBuff << 8) | (thech & 0xFF);
 14336      bsLive += 8;
 14337    }
 338
 339    int BsR(int n)
 340    {
 28341       while (bsLive < n) {
 14342        FillBuffer();
 343      }
 344
 14345      int v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1);
 14346      bsLive -= n;
 14347      return v;
 348    }
 349
 350    char BsGetUChar()
 351    {
 10352      return (char)BsR(8);
 353    }
 354
 355    int BsGetIntVS(int numBits)
 356    {
 0357      return BsR(numBits);
 358    }
 359
 360    int BsGetInt32()
 361    {
 1362      int result = BsR(8);
 1363      result = (result << 8) | BsR(8);
 1364      result = (result << 8) | BsR(8);
 1365      result = (result << 8) | BsR(8);
 1366      return result;
 367    }
 368
 369    void RecvDecodingTables()
 370    {
 0371      char[][] len = new char[BZip2Constants.GroupCount][];
 0372       for (int i = 0; i < BZip2Constants.GroupCount; ++i) {
 0373        len[i] = new char[BZip2Constants.MaximumAlphaSize];
 374      }
 375
 0376      bool[] inUse16 = new bool[16];
 377
 378      //--- Receive the mapping table ---
 0379       for (int i = 0; i < 16; i++) {
 0380        inUse16[i] = (BsR(1) == 1);
 381      }
 382
 0383       for (int i = 0; i < 16; i++) {
 0384         if (inUse16[i]) {
 0385           for (int j = 0; j < 16; j++) {
 0386            inUse[i * 16 + j] = (BsR(1) == 1);
 387          }
 0388        } else {
 0389           for (int j = 0; j < 16; j++) {
 0390            inUse[i * 16 + j] = false;
 391          }
 392        }
 393      }
 394
 0395      MakeMaps();
 0396      int alphaSize = nInUse + 2;
 397
 398      //--- Now the selectors ---
 0399      int nGroups = BsR(3);
 0400      int nSelectors = BsR(15);
 401
 0402       for (int i = 0; i < nSelectors; i++) {
 0403        int j = 0;
 0404         while (BsR(1) == 1) {
 0405          j++;
 406        }
 0407        selectorMtf[i] = (byte)j;
 408      }
 409
 410      //--- Undo the MTF values for the selectors. ---
 0411      byte[] pos = new byte[BZip2Constants.GroupCount];
 0412       for (int v = 0; v < nGroups; v++) {
 0413        pos[v] = (byte)v;
 414      }
 415
 0416       for (int i = 0; i < nSelectors; i++) {
 0417        int v = selectorMtf[i];
 0418        byte tmp = pos[v];
 0419         while (v > 0) {
 0420          pos[v] = pos[v - 1];
 0421          v--;
 422        }
 0423        pos[0] = tmp;
 0424        selector[i] = tmp;
 425      }
 426
 427      //--- Now the coding tables ---
 0428       for (int t = 0; t < nGroups; t++) {
 0429        int curr = BsR(5);
 0430         for (int i = 0; i < alphaSize; i++) {
 0431           while (BsR(1) == 1) {
 0432             if (BsR(1) == 0) {
 0433              curr++;
 0434            } else {
 0435              curr--;
 436            }
 437          }
 0438          len[t][i] = (char)curr;
 439        }
 440      }
 441
 442      //--- Create the Huffman decoding tables ---
 0443       for (int t = 0; t < nGroups; t++) {
 0444        int minLen = 32;
 0445        int maxLen = 0;
 0446         for (int i = 0; i < alphaSize; i++) {
 0447          maxLen = Math.Max(maxLen, len[t][i]);
 0448          minLen = Math.Min(minLen, len[t][i]);
 449        }
 0450        HbCreateDecodeTables(limit[t], baseArray[t], perm[t], len[t], minLen, maxLen, alphaSize);
 0451        minLens[t] = minLen;
 452      }
 0453    }
 454
 455    void GetAndMoveToFrontDecode()
 456    {
 0457      byte[] yy = new byte[256];
 458      int nextSym;
 459
 0460      int limitLast = BZip2Constants.BaseBlockSize * blockSize100k;
 0461      origPtr = BsGetIntVS(24);
 462
 0463      RecvDecodingTables();
 0464      int EOB = nInUse + 1;
 0465      int groupNo = -1;
 0466      int groupPos = 0;
 467
 468      /*--
 469      Setting up the unzftab entries here is not strictly
 470      necessary, but it does save having to do it later
 471      in a separate pass, and so saves a block's worth of
 472      cache misses.
 473      --*/
 0474       for (int i = 0; i <= 255; i++) {
 0475        unzftab[i] = 0;
 476      }
 477
 0478       for (int i = 0; i <= 255; i++) {
 0479        yy[i] = (byte)i;
 480      }
 481
 0482      last = -1;
 483
 0484       if (groupPos == 0) {
 0485        groupNo++;
 0486        groupPos = BZip2Constants.GroupSize;
 487      }
 488
 0489      groupPos--;
 0490      int zt = selector[groupNo];
 0491      int zn = minLens[zt];
 0492      int zvec = BsR(zn);
 493      int zj;
 494
 0495       while (zvec > limit[zt][zn]) {
 0496         if (zn > 20) { // the longest code
 0497          throw new BZip2Exception("Bzip data error");
 498        }
 0499        zn++;
 0500         while (bsLive < 1) {
 0501          FillBuffer();
 502        }
 0503        zj = (bsBuff >> (bsLive - 1)) & 1;
 0504        bsLive--;
 0505        zvec = (zvec << 1) | zj;
 506      }
 0507       if (zvec - baseArray[zt][zn] < 0 || zvec - baseArray[zt][zn] >= BZip2Constants.MaximumAlphaSize) {
 0508        throw new BZip2Exception("Bzip data error");
 509      }
 0510      nextSym = perm[zt][zvec - baseArray[zt][zn]];
 511
 512      while (true) {
 0513         if (nextSym == EOB) {
 514          break;
 515        }
 516
 0517         if (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB) {
 0518          int s = -1;
 0519          int n = 1;
 520          do {
 0521             if (nextSym == BZip2Constants.RunA) {
 0522              s += (0 + 1) * n;
 0523             } else if (nextSym == BZip2Constants.RunB) {
 0524              s += (1 + 1) * n;
 525            }
 526
 0527            n <<= 1;
 528
 0529             if (groupPos == 0) {
 0530              groupNo++;
 0531              groupPos = BZip2Constants.GroupSize;
 532            }
 533
 0534            groupPos--;
 535
 0536            zt = selector[groupNo];
 0537            zn = minLens[zt];
 0538            zvec = BsR(zn);
 539
 0540             while (zvec > limit[zt][zn]) {
 0541              zn++;
 0542               while (bsLive < 1) {
 0543                FillBuffer();
 544              }
 0545              zj = (bsBuff >> (bsLive - 1)) & 1;
 0546              bsLive--;
 0547              zvec = (zvec << 1) | zj;
 548            }
 0549            nextSym = perm[zt][zvec - baseArray[zt][zn]];
 0550           } while (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB);
 551
 0552          s++;
 0553          byte ch = seqToUnseq[yy[0]];
 0554          unzftab[ch] += s;
 555
 0556           while (s > 0) {
 0557            last++;
 0558            ll8[last] = ch;
 0559            s--;
 560          }
 561
 0562           if (last >= limitLast) {
 0563            BlockOverrun();
 564          }
 0565          continue;
 566        } else {
 0567          last++;
 0568           if (last >= limitLast) {
 0569            BlockOverrun();
 570          }
 571
 0572          byte tmp = yy[nextSym - 1];
 0573          unzftab[seqToUnseq[tmp]]++;
 0574          ll8[last] = seqToUnseq[tmp];
 575
 0576           for (int j = nextSym - 1; j > 0; --j) {
 0577            yy[j] = yy[j - 1];
 578          }
 0579          yy[0] = tmp;
 580
 0581           if (groupPos == 0) {
 0582            groupNo++;
 0583            groupPos = BZip2Constants.GroupSize;
 584          }
 585
 0586          groupPos--;
 0587          zt = selector[groupNo];
 0588          zn = minLens[zt];
 0589          zvec = BsR(zn);
 0590           while (zvec > limit[zt][zn]) {
 0591            zn++;
 0592             while (bsLive < 1) {
 0593              FillBuffer();
 594            }
 0595            zj = (bsBuff >> (bsLive - 1)) & 1;
 0596            bsLive--;
 0597            zvec = (zvec << 1) | zj;
 598          }
 0599          nextSym = perm[zt][zvec - baseArray[zt][zn]];
 0600          continue;
 601        }
 602      }
 0603    }
 604
 605    void SetupBlock()
 606    {
 1607      int[] cftab = new int[257];
 608
 1609      cftab[0] = 0;
 1610      Array.Copy(unzftab, 0, cftab, 1, 256);
 611
 514612       for (int i = 1; i <= 256; i++) {
 256613        cftab[i] += cftab[i - 1];
 614      }
 615
 4616       for (int i = 0; i <= last; i++) {
 1617        byte ch = ll8[i];
 1618        tt[cftab[ch]] = i;
 1619        cftab[ch]++;
 620      }
 621
 1622      cftab = null;
 623
 1624      tPos = tt[origPtr];
 625
 1626      count = 0;
 1627      i2 = 0;
 1628      ch2 = 256;   /*-- not a char and not EOF --*/
 629
 1630       if (blockRandomised) {
 0631        rNToGo = 0;
 0632        rTPos = 0;
 0633        SetupRandPartA();
 0634      } else {
 1635        SetupNoRandPartA();
 636      }
 1637    }
 638
 639    void SetupRandPartA()
 640    {
 0641       if (i2 <= last) {
 0642        chPrev = ch2;
 0643        ch2 = ll8[tPos];
 0644        tPos = tt[tPos];
 0645         if (rNToGo == 0) {
 0646          rNToGo = BZip2Constants.RandomNumbers[rTPos];
 0647          rTPos++;
 0648           if (rTPos == 512) {
 0649            rTPos = 0;
 650          }
 651        }
 0652        rNToGo--;
 0653         ch2 ^= (int)((rNToGo == 1) ? 1 : 0);
 0654        i2++;
 655
 0656        currentChar = ch2;
 0657        currentState = RAND_PART_B_STATE;
 0658        mCrc.Update(ch2);
 0659      } else {
 0660        EndBlock();
 0661        InitBlock();
 0662        SetupBlock();
 663      }
 0664    }
 665
 666    void SetupNoRandPartA()
 667    {
 1668       if (i2 <= last) {
 1669        chPrev = ch2;
 1670        ch2 = ll8[tPos];
 1671        tPos = tt[tPos];
 1672        i2++;
 673
 1674        currentChar = ch2;
 1675        currentState = NO_RAND_PART_B_STATE;
 1676        mCrc.Update(ch2);
 1677      } else {
 0678        EndBlock();
 0679        InitBlock();
 0680        SetupBlock();
 681      }
 0682    }
 683
 684    void SetupRandPartB()
 685    {
 0686       if (ch2 != chPrev) {
 0687        currentState = RAND_PART_A_STATE;
 0688        count = 1;
 0689        SetupRandPartA();
 0690      } else {
 0691        count++;
 0692         if (count >= 4) {
 0693          z = ll8[tPos];
 0694          tPos = tt[tPos];
 0695           if (rNToGo == 0) {
 0696            rNToGo = BZip2Constants.RandomNumbers[rTPos];
 0697            rTPos++;
 0698             if (rTPos == 512) {
 0699              rTPos = 0;
 700            }
 701          }
 0702          rNToGo--;
 0703           z ^= (byte)((rNToGo == 1) ? 1 : 0);
 0704          j2 = 0;
 0705          currentState = RAND_PART_C_STATE;
 0706          SetupRandPartC();
 0707        } else {
 0708          currentState = RAND_PART_A_STATE;
 0709          SetupRandPartA();
 710        }
 711      }
 0712    }
 713
 714    void SetupRandPartC()
 715    {
 0716       if (j2 < (int)z) {
 0717        currentChar = ch2;
 0718        mCrc.Update(ch2);
 0719        j2++;
 0720      } else {
 0721        currentState = RAND_PART_A_STATE;
 0722        i2++;
 0723        count = 0;
 0724        SetupRandPartA();
 725      }
 0726    }
 727
 728    void SetupNoRandPartB()
 729    {
 0730       if (ch2 != chPrev) {
 0731        currentState = NO_RAND_PART_A_STATE;
 0732        count = 1;
 0733        SetupNoRandPartA();
 0734      } else {
 0735        count++;
 0736         if (count >= 4) {
 0737          z = ll8[tPos];
 0738          tPos = tt[tPos];
 0739          currentState = NO_RAND_PART_C_STATE;
 0740          j2 = 0;
 0741          SetupNoRandPartC();
 0742        } else {
 0743          currentState = NO_RAND_PART_A_STATE;
 0744          SetupNoRandPartA();
 745        }
 746      }
 0747    }
 748
 749    void SetupNoRandPartC()
 750    {
 0751       if (j2 < (int)z) {
 0752        currentChar = ch2;
 0753        mCrc.Update(ch2);
 0754        j2++;
 0755      } else {
 0756        currentState = NO_RAND_PART_A_STATE;
 0757        i2++;
 0758        count = 0;
 0759        SetupNoRandPartA();
 760      }
 0761    }
 762
 763    void SetDecompressStructureSizes(int newSize100k)
 764    {
 1765       if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && blockSize100k <= 9)) {
 0766        throw new BZip2Exception("Invalid block size");
 767      }
 768
 1769      blockSize100k = newSize100k;
 770
 1771       if (newSize100k == 0) {
 0772        return;
 773      }
 774
 1775      int n = BZip2Constants.BaseBlockSize * newSize100k;
 1776      ll8 = new byte[n];
 1777      tt = new int[n];
 1778    }
 779
 780    static void CompressedStreamEOF()
 781    {
 0782      throw new EndOfStreamException("BZip2 input stream end of compressed stream");
 783    }
 784
 785    static void BlockOverrun()
 786    {
 0787      throw new BZip2Exception("BZip2 input stream block overrun");
 788    }
 789
 790    static void BadBlockHeader()
 791    {
 0792      throw new BZip2Exception("BZip2 input stream bad block header");
 793    }
 794
 795    static void CrcError()
 796    {
 0797      throw new BZip2Exception("BZip2 input stream crc error");
 798    }
 799
 800    static void HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen, int maxLen, in
 801    {
 0802      int pp = 0;
 803
 0804       for (int i = minLen; i <= maxLen; ++i) {
 0805         for (int j = 0; j < alphaSize; ++j) {
 0806           if (length[j] == i) {
 0807            perm[pp] = j;
 0808            ++pp;
 809          }
 810        }
 811      }
 812
 0813       for (int i = 0; i < BZip2Constants.MaximumCodeLength; i++) {
 0814        baseArray[i] = 0;
 815      }
 816
 0817       for (int i = 0; i < alphaSize; i++) {
 0818        ++baseArray[length[i] + 1];
 819      }
 820
 0821       for (int i = 1; i < BZip2Constants.MaximumCodeLength; i++) {
 0822        baseArray[i] += baseArray[i - 1];
 823      }
 824
 0825       for (int i = 0; i < BZip2Constants.MaximumCodeLength; i++) {
 0826        limit[i] = 0;
 827      }
 828
 0829      int vec = 0;
 830
 0831       for (int i = minLen; i <= maxLen; i++) {
 0832        vec += (baseArray[i + 1] - baseArray[i]);
 0833        limit[i] = vec - 1;
 0834        vec <<= 1;
 835      }
 836
 0837       for (int i = minLen + 1; i <= maxLen; i++) {
 0838        baseArray[i] = ((limit[i - 1] + 1) << 1) - baseArray[i];
 839      }
 0840    }
 841
 842    #region Instance Fields
 843    /*--
 844    index of the last char in the block, so
 845    the block size == last + 1.
 846    --*/
 847    int last;
 848
 849    /*--
 850    index in zptr[] of original string after sorting.
 851    --*/
 852    int origPtr;
 853
 854    /*--
 855    always: in the range 0 .. 9.
 856    The current block size is 100000 * this number.
 857    --*/
 858    int blockSize100k;
 859
 860    bool blockRandomised;
 861
 862    int bsBuff;
 863    int bsLive;
 1864    IChecksum mCrc = new BZip2Crc();
 865
 1866    bool[] inUse = new bool[256];
 867    int nInUse;
 868
 1869    byte[] seqToUnseq = new byte[256];
 1870    byte[] unseqToSeq = new byte[256];
 871
 1872    byte[] selector = new byte[BZip2Constants.MaximumSelectors];
 1873    byte[] selectorMtf = new byte[BZip2Constants.MaximumSelectors];
 874
 875    int[] tt;
 876    byte[] ll8;
 877
 878    /*--
 879    freq table collected to save a pass over the data
 880    during decompression.
 881    --*/
 1882    int[] unzftab = new int[256];
 883
 1884    int[][] limit = new int[BZip2Constants.GroupCount][];
 1885    int[][] baseArray = new int[BZip2Constants.GroupCount][];
 1886    int[][] perm = new int[BZip2Constants.GroupCount][];
 1887    int[] minLens = new int[BZip2Constants.GroupCount];
 888
 889    Stream baseStream;
 890    bool streamEnd;
 891
 1892    int currentChar = -1;
 893
 1894    int currentState = START_BLOCK_STATE;
 895
 896    int storedBlockCRC, storedCombinedCRC;
 897    int computedBlockCRC;
 898    uint computedCombinedCRC;
 899
 900    int count, chPrev, ch2;
 901    int tPos;
 902    int rNToGo;
 903    int rTPos;
 904    int i2, j2;
 905    byte z;
 1906    bool isStreamOwner = true;
 907    #endregion
 908  }
 909}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_BZip2OutputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_BZip2OutputStream.htm new file mode 100644 index 000000000..6578a992a --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_BZip2OutputStream.htm @@ -0,0 +1,1873 @@ + + + + +ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2OutputStream.cs
Covered lines:107
Uncovered lines:794
Coverable lines:901
Total lines:1793
Line coverage:11.8%
Branch coverage:3.6%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)390.9160
Finalize()100
Seek(...)100
SetLength(...)100
ReadByte()100
Read(...)100
Write(...)600
WriteByte(...)400
Close()1100100
MakeMaps()300
WriteRun()700
Dispose(...)593.3355.56
Flush()1100100
Initialize()1100100
InitBlock()2100100
EndBlock()31040
EndCompression()1100100
BsSetStream(...)1100100
BsFinishedWithStream()2100100
BsW(...)2100100
BsPutUChar(...)1100100
BsPutint(...)1100100
BsPutIntVS(...)100
SendMTFValues()6700
MoveToFrontCodeAndSend()100
SimpleSort(...)1500
Vswap(...)200
QSort3(...)1700
MainSort()3200
RandomiseBlock()700
DoReversibleTransformation()600
FullGtU(...)1800
AllocateCompressStructures()410057.14
GenerateMTFValues()1400
Panic()100
HbMakeCodeLengths(...)2300
HbAssignCodes(...)400
Med3(...)400
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\BZip2\BZip2OutputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using ICSharpCode.SharpZipLib.Checksum;
 4
 5namespace ICSharpCode.SharpZipLib.BZip2
 6{
 7  /// <summary>
 8  /// An output stream that compresses into the BZip2 format
 9  /// including file header chars into another stream.
 10  /// </summary>
 11  public class BZip2OutputStream : Stream
 12  {
 13    #region Constants
 14    const int SETMASK = (1 << 21);
 15    const int CLEARMASK = (~SETMASK);
 16    const int GREATER_ICOST = 15;
 17    const int LESSER_ICOST = 0;
 18    const int SMALL_THRESH = 20;
 19    const int DEPTH_THRESH = 10;
 20
 21    /*--
 22    If you are ever unlucky/improbable enough
 23    to get a stack overflow whilst sorting,
 24    increase the following constant and try
 25    again.  In practice I have never seen the
 26    stack go above 27 elems, so the following
 27    limit seems very generous.
 28    --*/
 29    const int QSORT_STACK_SIZE = 1000;
 30
 31    /*--
 32    Knuth's increments seem to work better
 33    than Incerpi-Sedgewick here.  Possibly
 34    because the number of elems to sort is
 35    usually small, typically <= 20.
 36    --*/
 137    readonly int[] increments = {
 138                          1, 4, 13, 40, 121, 364, 1093, 3280,
 139                          9841, 29524, 88573, 265720,
 140                          797161, 2391484
 141                        };
 42    #endregion
 43
 44    #region Constructors
 45    /// <summary>
 46    /// Construct a default output stream with maximum block size
 47    /// </summary>
 48    /// <param name="stream">The stream to write BZip data onto.</param>
 149    public BZip2OutputStream(Stream stream) : this(stream, 9)
 50    {
 151    }
 52
 53    /// <summary>
 54    /// Initialise a new instance of the <see cref="BZip2OutputStream"></see>
 55    /// for the specified stream, using the given blocksize.
 56    /// </summary>
 57    /// <param name="stream">The stream to write compressed data to.</param>
 58    /// <param name="blockSize">The block size to use.</param>
 59    /// <remarks>
 60    /// Valid block sizes are in the range 1..9, with 1 giving
 61    /// the lowest compression and 9 the highest.
 62    /// </remarks>
 163    public BZip2OutputStream(Stream stream, int blockSize)
 64    {
 165      BsSetStream(stream);
 66
 167      workFactor = 50;
 168       if (blockSize > 9) {
 069        blockSize = 9;
 70      }
 71
 172       if (blockSize < 1) {
 073        blockSize = 1;
 74      }
 175      blockSize100k = blockSize;
 176      AllocateCompressStructures();
 177      Initialize();
 178      InitBlock();
 179    }
 80    #endregion
 81
 82    #region Destructor
 83    /// <summary>
 84    /// Ensures that resources are freed and other cleanup operations
 85    /// are performed when the garbage collector reclaims the BZip2OutputStream.
 86    /// </summary>
 87    ~BZip2OutputStream()
 88    {
 089      Dispose(false);
 090    }
 91    #endregion
 92
 93    /// <summary>
 94    /// Get/set flag indicating ownership of underlying stream.
 95    /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
 96    /// </summary>
 97    public bool IsStreamOwner {
 198      get { return isStreamOwner; }
 099      set { isStreamOwner = value; }
 100    }
 101
 102
 103    #region Stream overrides
 104    /// <summary>
 105    /// Gets a value indicating whether the current stream supports reading
 106    /// </summary>
 107    public override bool CanRead {
 108      get {
 0109        return false;
 110      }
 111    }
 112
 113    /// <summary>
 114    /// Gets a value indicating whether the current stream supports seeking
 115    /// </summary>
 116    public override bool CanSeek {
 117      get {
 0118        return false;
 119      }
 120    }
 121
 122    /// <summary>
 123    /// Gets a value indicating whether the current stream supports writing
 124    /// </summary>
 125    public override bool CanWrite {
 126      get {
 0127        return baseStream.CanWrite;
 128      }
 129    }
 130
 131    /// <summary>
 132    /// Gets the length in bytes of the stream
 133    /// </summary>
 134    public override long Length {
 135      get {
 0136        return baseStream.Length;
 137      }
 138    }
 139
 140    /// <summary>
 141    /// Gets or sets the current position of this stream.
 142    /// </summary>
 143    public override long Position {
 144      get {
 0145        return baseStream.Position;
 146      }
 147      set {
 0148        throw new NotSupportedException("BZip2OutputStream position cannot be set");
 149      }
 150    }
 151
 152    /// <summary>
 153    /// Sets the current position of this stream to the given value.
 154    /// </summary>
 155    /// <param name="offset">The point relative to the offset from which to being seeking.</param>
 156    /// <param name="origin">The reference point from which to begin seeking.</param>
 157    /// <returns>The new position in the stream.</returns>
 158    public override long Seek(long offset, SeekOrigin origin)
 159    {
 0160      throw new NotSupportedException("BZip2OutputStream Seek not supported");
 161    }
 162
 163    /// <summary>
 164    /// Sets the length of this stream to the given value.
 165    /// </summary>
 166    /// <param name="value">The new stream length.</param>
 167    public override void SetLength(long value)
 168    {
 0169      throw new NotSupportedException("BZip2OutputStream SetLength not supported");
 170    }
 171
 172    /// <summary>
 173    /// Read a byte from the stream advancing the position.
 174    /// </summary>
 175    /// <returns>The byte read cast to an int; -1 if end of stream.</returns>
 176    public override int ReadByte()
 177    {
 0178      throw new NotSupportedException("BZip2OutputStream ReadByte not supported");
 179    }
 180
 181    /// <summary>
 182    /// Read a block of bytes
 183    /// </summary>
 184    /// <param name="buffer">The buffer to read into.</param>
 185    /// <param name="offset">The offset in the buffer to start storing data at.</param>
 186    /// <param name="count">The maximum number of bytes to read.</param>
 187    /// <returns>The total number of bytes read. This might be less than the number of bytes
 188    /// requested if that number of bytes are not currently available, or zero
 189    /// if the end of the stream is reached.</returns>
 190    public override int Read(byte[] buffer, int offset, int count)
 191    {
 0192      throw new NotSupportedException("BZip2OutputStream Read not supported");
 193    }
 194
 195    /// <summary>
 196    /// Write a block of bytes to the stream
 197    /// </summary>
 198    /// <param name="buffer">The buffer containing data to write.</param>
 199    /// <param name="offset">The offset of the first byte to write.</param>
 200    /// <param name="count">The number of bytes to write.</param>
 201    public override void Write(byte[] buffer, int offset, int count)
 202    {
 0203       if (buffer == null) {
 0204        throw new ArgumentNullException(nameof(buffer));
 205      }
 206
 0207       if (offset < 0) {
 0208        throw new ArgumentOutOfRangeException(nameof(offset));
 209      }
 210
 0211       if (count < 0) {
 0212        throw new ArgumentOutOfRangeException(nameof(count));
 213      }
 214
 0215       if (buffer.Length - offset < count) {
 0216        throw new ArgumentException("Offset/count out of range");
 217      }
 218
 0219       for (int i = 0; i < count; ++i) {
 0220        WriteByte(buffer[offset + i]);
 221      }
 0222    }
 223
 224    /// <summary>
 225    /// Write a byte to the stream.
 226    /// </summary>
 227    /// <param name="value">The byte to write to the stream.</param>
 228    public override void WriteByte(byte value)
 229    {
 0230      int b = (256 + value) % 256;
 0231       if (currentChar != -1) {
 0232         if (currentChar == b) {
 0233          runLength++;
 0234           if (runLength > 254) {
 0235            WriteRun();
 0236            currentChar = -1;
 0237            runLength = 0;
 238          }
 0239        } else {
 0240          WriteRun();
 0241          runLength = 1;
 0242          currentChar = b;
 243        }
 0244      } else {
 0245        currentChar = b;
 0246        runLength++;
 247      }
 0248    }
 249
 250    /// <summary>
 251    /// End the current block and end compression.
 252    /// Close the stream and free any resources
 253    /// </summary>
 254    public override void Close()
 255    {
 1256      Dispose(true);
 1257      GC.SuppressFinalize(this);
 1258    }
 259
 260    #endregion
 261    void MakeMaps()
 262    {
 0263      nInUse = 0;
 0264       for (int i = 0; i < 256; i++) {
 0265         if (inUse[i]) {
 0266          seqToUnseq[nInUse] = (char)i;
 0267          unseqToSeq[i] = (char)nInUse;
 0268          nInUse++;
 269        }
 270      }
 0271    }
 272
 273    /// <summary>
 274    /// Get the number of bytes written to output.
 275    /// </summary>
 276    void WriteRun()
 277    {
 0278       if (last < allowableBlockSize) {
 0279        inUse[currentChar] = true;
 0280         for (int i = 0; i < runLength; i++) {
 0281          mCrc.Update(currentChar);
 282        }
 283
 0284         switch (runLength) {
 285          case 1:
 0286            last++;
 0287            block[last + 1] = (byte)currentChar;
 0288            break;
 289          case 2:
 0290            last++;
 0291            block[last + 1] = (byte)currentChar;
 0292            last++;
 0293            block[last + 1] = (byte)currentChar;
 0294            break;
 295          case 3:
 0296            last++;
 0297            block[last + 1] = (byte)currentChar;
 0298            last++;
 0299            block[last + 1] = (byte)currentChar;
 0300            last++;
 0301            block[last + 1] = (byte)currentChar;
 0302            break;
 303          default:
 0304            inUse[runLength - 4] = true;
 0305            last++;
 0306            block[last + 1] = (byte)currentChar;
 0307            last++;
 0308            block[last + 1] = (byte)currentChar;
 0309            last++;
 0310            block[last + 1] = (byte)currentChar;
 0311            last++;
 0312            block[last + 1] = (byte)currentChar;
 0313            last++;
 0314            block[last + 1] = (byte)(runLength - 4);
 0315            break;
 316        }
 317      } else {
 0318        EndBlock();
 0319        InitBlock();
 0320        WriteRun();
 321      }
 0322    }
 323
 324    /// <summary>
 325    /// Get the number of bytes written to the output.
 326    /// </summary>
 327    public int BytesWritten {
 0328      get { return bytesOut; }
 329    }
 330
 331    /// <summary>
 332    /// Releases the unmanaged resources used by the <see cref="BZip2OutputStream"/> and optionally releases the managed
 333    /// </summary>
 334    /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged re
 335    override protected void Dispose(bool disposing)
 336    {
 337      try {
 1338        base.Dispose(disposing);
 1339         if (!disposed_) {
 1340          disposed_ = true;
 341
 1342           if (runLength > 0) {
 0343            WriteRun();
 344          }
 345
 1346          currentChar = -1;
 1347          EndBlock();
 1348          EndCompression();
 1349          Flush();
 350        }
 1351      } finally {
 1352         if (disposing) {
 1353           if (IsStreamOwner) {
 1354            baseStream.Close();
 355          }
 356        }
 1357      }
 1358    }
 359
 360    /// <summary>
 361    /// Flush output buffers
 362    /// </summary>
 363    public override void Flush()
 364    {
 1365      baseStream.Flush();
 1366    }
 367
 368    void Initialize()
 369    {
 1370      bytesOut = 0;
 1371      nBlocksRandomised = 0;
 372
 373      /*--- Write header `magic' bytes indicating file-format == huffmanised,
 374      followed by a digit indicating blockSize100k.
 375      ---*/
 376
 1377      BsPutUChar('B');
 1378      BsPutUChar('Z');
 379
 1380      BsPutUChar('h');
 1381      BsPutUChar('0' + blockSize100k);
 382
 1383      combinedCRC = 0;
 1384    }
 385
 386    void InitBlock()
 387    {
 1388      mCrc.Reset();
 1389      last = -1;
 390
 514391       for (int i = 0; i < 256; i++) {
 256392        inUse[i] = false;
 393      }
 394
 395      /*--- 20 is just a paranoia constant ---*/
 1396      allowableBlockSize = BZip2Constants.BaseBlockSize * blockSize100k - 20;
 1397    }
 398
 399    void EndBlock()
 400    {
 1401       if (last < 0) {       // dont do anything for empty files, (makes empty files compatible with original Bzip)
 1402        return;
 403      }
 404
 0405      blockCRC = unchecked((uint)mCrc.Value);
 0406      combinedCRC = (combinedCRC << 1) | (combinedCRC >> 31);
 0407      combinedCRC ^= blockCRC;
 408
 409      /*-- sort the block and establish position of original string --*/
 0410      DoReversibleTransformation();
 411
 412      /*--
 413      A 6-byte block header, the value chosen arbitrarily
 414      as 0x314159265359 :-).  A 32 bit value does not really
 415      give a strong enough guarantee that the value will not
 416      appear by chance in the compressed datastream.  Worst-case
 417      probability of this event, for a 900k block, is about
 418      2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.
 419      For a compressed file of size 100Gb -- about 100000 blocks --
 420      only a 48-bit marker will do.  NB: normal compression/
 421      decompression do *not* rely on these statistical properties.
 422      They are only important when trying to recover blocks from
 423      damaged files.
 424      --*/
 0425      BsPutUChar(0x31);
 0426      BsPutUChar(0x41);
 0427      BsPutUChar(0x59);
 0428      BsPutUChar(0x26);
 0429      BsPutUChar(0x53);
 0430      BsPutUChar(0x59);
 431
 432      /*-- Now the block's CRC, so it is in a known place. --*/
 433      unchecked {
 0434        BsPutint((int)blockCRC);
 435      }
 436
 437      /*-- Now a single bit indicating randomisation. --*/
 0438       if (blockRandomised) {
 0439        BsW(1, 1);
 0440        nBlocksRandomised++;
 0441      } else {
 0442        BsW(1, 0);
 443      }
 444
 445      /*-- Finally, block's contents proper. --*/
 0446      MoveToFrontCodeAndSend();
 0447    }
 448
 449    void EndCompression()
 450    {
 451      /*--
 452      Now another magic 48-bit number, 0x177245385090, to
 453      indicate the end of the last block.  (sqrt(pi), if
 454      you want to know.  I did want to use e, but it contains
 455      too much repetition -- 27 18 28 18 28 46 -- for me
 456      to feel statistically comfortable.  Call me paranoid.)
 457      --*/
 1458      BsPutUChar(0x17);
 1459      BsPutUChar(0x72);
 1460      BsPutUChar(0x45);
 1461      BsPutUChar(0x38);
 1462      BsPutUChar(0x50);
 1463      BsPutUChar(0x90);
 464
 465      unchecked {
 1466        BsPutint((int)combinedCRC);
 467      }
 468
 1469      BsFinishedWithStream();
 1470    }
 471
 472    void BsSetStream(Stream stream)
 473    {
 1474      baseStream = stream;
 1475      bsLive = 0;
 1476      bsBuff = 0;
 1477      bytesOut = 0;
 1478    }
 479
 480    void BsFinishedWithStream()
 481    {
 2482       while (bsLive > 0) {
 1483        int ch = (bsBuff >> 24);
 1484        baseStream.WriteByte((byte)ch); // write 8-bit
 1485        bsBuff <<= 8;
 1486        bsLive -= 8;
 1487        bytesOut++;
 488      }
 1489    }
 490
 491    void BsW(int n, int v)
 492    {
 27493       while (bsLive >= 8) {
 13494        int ch = (bsBuff >> 24);
 13495        unchecked { baseStream.WriteByte((byte)ch); } // write 8-bit
 13496        bsBuff <<= 8;
 13497        bsLive -= 8;
 13498        ++bytesOut;
 499      }
 14500      bsBuff |= (v << (32 - bsLive - n));
 14501      bsLive += n;
 14502    }
 503
 504    void BsPutUChar(int c)
 505    {
 10506      BsW(8, c);
 10507    }
 508
 509    void BsPutint(int u)
 510    {
 1511      BsW(8, (u >> 24) & 0xFF);
 1512      BsW(8, (u >> 16) & 0xFF);
 1513      BsW(8, (u >> 8) & 0xFF);
 1514      BsW(8, u & 0xFF);
 1515    }
 516
 517    void BsPutIntVS(int numBits, int c)
 518    {
 0519      BsW(numBits, c);
 0520    }
 521
 522    void SendMTFValues()
 523    {
 0524      char[][] len = new char[BZip2Constants.GroupCount][];
 0525       for (int i = 0; i < BZip2Constants.GroupCount; ++i) {
 0526        len[i] = new char[BZip2Constants.MaximumAlphaSize];
 527      }
 528
 529      int gs, ge, totc, bt, bc, iter;
 0530      int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;
 531      int nGroups;
 532
 0533      alphaSize = nInUse + 2;
 0534       for (int t = 0; t < BZip2Constants.GroupCount; t++) {
 0535         for (int v = 0; v < alphaSize; v++) {
 0536          len[t][v] = (char)GREATER_ICOST;
 537        }
 538      }
 539
 540      /*--- Decide how many coding tables to use ---*/
 0541       if (nMTF <= 0) {
 0542        Panic();
 543      }
 544
 0545       if (nMTF < 200) {
 0546        nGroups = 2;
 0547       } else if (nMTF < 600) {
 0548        nGroups = 3;
 0549       } else if (nMTF < 1200) {
 0550        nGroups = 4;
 0551       } else if (nMTF < 2400) {
 0552        nGroups = 5;
 0553      } else {
 0554        nGroups = 6;
 555      }
 556
 557      /*--- Generate an initial set of coding tables ---*/
 0558      int nPart = nGroups;
 0559      int remF = nMTF;
 0560      gs = 0;
 0561       while (nPart > 0) {
 0562        int tFreq = remF / nPart;
 0563        int aFreq = 0;
 0564        ge = gs - 1;
 0565         while (aFreq < tFreq && ge < alphaSize - 1) {
 0566          ge++;
 0567          aFreq += mtfFreq[ge];
 568        }
 569
 0570         if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) {
 0571          aFreq -= mtfFreq[ge];
 0572          ge--;
 573        }
 574
 0575         for (int v = 0; v < alphaSize; v++) {
 0576           if (v >= gs && v <= ge) {
 0577            len[nPart - 1][v] = (char)LESSER_ICOST;
 0578          } else {
 0579            len[nPart - 1][v] = (char)GREATER_ICOST;
 580          }
 581        }
 582
 0583        nPart--;
 0584        gs = ge + 1;
 0585        remF -= aFreq;
 586      }
 587
 0588      int[][] rfreq = new int[BZip2Constants.GroupCount][];
 0589       for (int i = 0; i < BZip2Constants.GroupCount; ++i) {
 0590        rfreq[i] = new int[BZip2Constants.MaximumAlphaSize];
 591      }
 592
 0593      int[] fave = new int[BZip2Constants.GroupCount];
 0594      short[] cost = new short[BZip2Constants.GroupCount];
 595      /*---
 596      Iterate up to N_ITERS times to improve the tables.
 597      ---*/
 0598       for (iter = 0; iter < BZip2Constants.NumberOfIterations; ++iter) {
 0599         for (int t = 0; t < nGroups; ++t) {
 0600          fave[t] = 0;
 601        }
 602
 0603         for (int t = 0; t < nGroups; ++t) {
 0604           for (int v = 0; v < alphaSize; ++v) {
 0605            rfreq[t][v] = 0;
 606          }
 607        }
 608
 0609        nSelectors = 0;
 0610        totc = 0;
 0611        gs = 0;
 0612        while (true) {
 613          /*--- Set group start & end marks. --*/
 0614           if (gs >= nMTF) {
 615            break;
 616          }
 0617          ge = gs + BZip2Constants.GroupSize - 1;
 0618           if (ge >= nMTF) {
 0619            ge = nMTF - 1;
 620          }
 621
 622          /*--
 623          Calculate the cost of this group as coded
 624          by each of the coding tables.
 625          --*/
 0626           for (int t = 0; t < nGroups; t++) {
 0627            cost[t] = 0;
 628          }
 629
 0630           if (nGroups == 6) {
 631            short cost0, cost1, cost2, cost3, cost4, cost5;
 0632            cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0;
 0633             for (int i = gs; i <= ge; ++i) {
 0634              short icv = szptr[i];
 0635              cost0 += (short)len[0][icv];
 0636              cost1 += (short)len[1][icv];
 0637              cost2 += (short)len[2][icv];
 0638              cost3 += (short)len[3][icv];
 0639              cost4 += (short)len[4][icv];
 0640              cost5 += (short)len[5][icv];
 641            }
 0642            cost[0] = cost0;
 0643            cost[1] = cost1;
 0644            cost[2] = cost2;
 0645            cost[3] = cost3;
 0646            cost[4] = cost4;
 0647            cost[5] = cost5;
 0648          } else {
 0649             for (int i = gs; i <= ge; ++i) {
 0650              short icv = szptr[i];
 0651               for (int t = 0; t < nGroups; t++) {
 0652                cost[t] += (short)len[t][icv];
 653              }
 654            }
 655          }
 656
 657          /*--
 658          Find the coding table which is best for this group,
 659          and record its identity in the selector table.
 660          --*/
 0661          bc = 999999999;
 0662          bt = -1;
 0663           for (int t = 0; t < nGroups; ++t) {
 0664             if (cost[t] < bc) {
 0665              bc = cost[t];
 0666              bt = t;
 667            }
 668          }
 0669          totc += bc;
 0670          fave[bt]++;
 0671          selector[nSelectors] = (char)bt;
 0672          nSelectors++;
 673
 674          /*--
 675          Increment the symbol frequencies for the selected table.
 676          --*/
 0677           for (int i = gs; i <= ge; ++i) {
 0678            ++rfreq[bt][szptr[i]];
 679          }
 680
 0681          gs = ge + 1;
 682        }
 683
 684        /*--
 685        Recompute the tables based on the accumulated frequencies.
 686        --*/
 0687         for (int t = 0; t < nGroups; ++t) {
 0688          HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);
 689        }
 690      }
 691
 0692      rfreq = null;
 0693      fave = null;
 0694      cost = null;
 695
 0696       if (!(nGroups < 8)) {
 0697        Panic();
 698      }
 699
 0700       if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.GroupSize)))) {
 0701        Panic();
 702      }
 703
 704      /*--- Compute MTF values for the selectors. ---*/
 0705      char[] pos = new char[BZip2Constants.GroupCount];
 706      char ll_i, tmp2, tmp;
 707
 0708       for (int i = 0; i < nGroups; i++) {
 0709        pos[i] = (char)i;
 710      }
 711
 0712       for (int i = 0; i < nSelectors; i++) {
 0713        ll_i = selector[i];
 0714        int j = 0;
 0715        tmp = pos[j];
 0716         while (ll_i != tmp) {
 0717          j++;
 0718          tmp2 = tmp;
 0719          tmp = pos[j];
 0720          pos[j] = tmp2;
 721        }
 0722        pos[0] = tmp;
 0723        selectorMtf[i] = (char)j;
 724      }
 725
 0726      int[][] code = new int[BZip2Constants.GroupCount][];
 727
 0728       for (int i = 0; i < BZip2Constants.GroupCount; ++i) {
 0729        code[i] = new int[BZip2Constants.MaximumAlphaSize];
 730      }
 731
 732      /*--- Assign actual codes for the tables. --*/
 0733       for (int t = 0; t < nGroups; t++) {
 0734        minLen = 32;
 0735        maxLen = 0;
 0736         for (int i = 0; i < alphaSize; i++) {
 0737           if (len[t][i] > maxLen) {
 0738            maxLen = len[t][i];
 739          }
 0740           if (len[t][i] < minLen) {
 0741            minLen = len[t][i];
 742          }
 743        }
 0744         if (maxLen > 20) {
 0745          Panic();
 746        }
 0747         if (minLen < 1) {
 0748          Panic();
 749        }
 0750        HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);
 751      }
 752
 753      /*--- Transmit the mapping table. ---*/
 0754      bool[] inUse16 = new bool[16];
 0755       for (int i = 0; i < 16; ++i) {
 0756        inUse16[i] = false;
 0757         for (int j = 0; j < 16; ++j) {
 0758           if (inUse[i * 16 + j]) {
 0759            inUse16[i] = true;
 760          }
 761        }
 762      }
 763
 0764       for (int i = 0; i < 16; ++i) {
 0765         if (inUse16[i]) {
 0766          BsW(1, 1);
 0767        } else {
 0768          BsW(1, 0);
 769        }
 770      }
 771
 0772       for (int i = 0; i < 16; ++i) {
 0773         if (inUse16[i]) {
 0774           for (int j = 0; j < 16; ++j) {
 0775             if (inUse[i * 16 + j]) {
 0776              BsW(1, 1);
 0777            } else {
 0778              BsW(1, 0);
 779            }
 780          }
 781        }
 782      }
 783
 784      /*--- Now the selectors. ---*/
 0785      BsW(3, nGroups);
 0786      BsW(15, nSelectors);
 0787       for (int i = 0; i < nSelectors; ++i) {
 0788         for (int j = 0; j < selectorMtf[i]; ++j) {
 0789          BsW(1, 1);
 790        }
 0791        BsW(1, 0);
 792      }
 793
 794      /*--- Now the coding tables. ---*/
 0795       for (int t = 0; t < nGroups; ++t) {
 0796        int curr = len[t][0];
 0797        BsW(5, curr);
 0798         for (int i = 0; i < alphaSize; ++i) {
 0799           while (curr < len[t][i]) {
 0800            BsW(2, 2);
 0801            curr++; /* 10 */
 802          }
 0803           while (curr > len[t][i]) {
 0804            BsW(2, 3);
 0805            curr--; /* 11 */
 806          }
 0807          BsW(1, 0);
 808        }
 809      }
 810
 811      /*--- And finally, the block data proper ---*/
 0812      selCtr = 0;
 0813      gs = 0;
 0814      while (true) {
 0815         if (gs >= nMTF) {
 816          break;
 817        }
 0818        ge = gs + BZip2Constants.GroupSize - 1;
 0819         if (ge >= nMTF) {
 0820          ge = nMTF - 1;
 821        }
 822
 0823         for (int i = gs; i <= ge; i++) {
 0824          BsW(len[selector[selCtr]][szptr[i]], code[selector[selCtr]][szptr[i]]);
 825        }
 826
 0827        gs = ge + 1;
 0828        ++selCtr;
 829      }
 0830       if (!(selCtr == nSelectors)) {
 0831        Panic();
 832      }
 0833    }
 834
 835    void MoveToFrontCodeAndSend()
 836    {
 0837      BsPutIntVS(24, origPtr);
 0838      GenerateMTFValues();
 0839      SendMTFValues();
 0840    }
 841
 842    void SimpleSort(int lo, int hi, int d)
 843    {
 844      int i, j, h, bigN, hp;
 845      int v;
 846
 0847      bigN = hi - lo + 1;
 0848       if (bigN < 2) {
 0849        return;
 850      }
 851
 0852      hp = 0;
 0853       while (increments[hp] < bigN) {
 0854        hp++;
 855      }
 0856      hp--;
 857
 0858       for (; hp >= 0; hp--) {
 0859        h = increments[hp];
 860
 0861        i = lo + h;
 862        while (true) {
 863          /*-- copy 1 --*/
 0864           if (i > hi)
 865            break;
 0866          v = zptr[i];
 0867          j = i;
 0868           while (FullGtU(zptr[j - h] + d, v + d)) {
 0869            zptr[j] = zptr[j - h];
 0870            j = j - h;
 0871             if (j <= (lo + h - 1))
 872              break;
 873          }
 0874          zptr[j] = v;
 0875          i++;
 876
 877          /*-- copy 2 --*/
 0878           if (i > hi) {
 879            break;
 880          }
 0881          v = zptr[i];
 0882          j = i;
 0883           while (FullGtU(zptr[j - h] + d, v + d)) {
 0884            zptr[j] = zptr[j - h];
 0885            j = j - h;
 0886             if (j <= (lo + h - 1)) {
 887              break;
 888            }
 889          }
 0890          zptr[j] = v;
 0891          i++;
 892
 893          /*-- copy 3 --*/
 0894           if (i > hi) {
 895            break;
 896          }
 0897          v = zptr[i];
 0898          j = i;
 0899           while (FullGtU(zptr[j - h] + d, v + d)) {
 0900            zptr[j] = zptr[j - h];
 0901            j = j - h;
 0902             if (j <= (lo + h - 1)) {
 903              break;
 904            }
 905          }
 0906          zptr[j] = v;
 0907          i++;
 908
 0909           if (workDone > workLimit && firstAttempt) {
 0910            return;
 911          }
 912        }
 913      }
 0914    }
 915
 916    void Vswap(int p1, int p2, int n)
 917    {
 0918      int temp = 0;
 0919       while (n > 0) {
 0920        temp = zptr[p1];
 0921        zptr[p1] = zptr[p2];
 0922        zptr[p2] = temp;
 0923        p1++;
 0924        p2++;
 0925        n--;
 926      }
 0927    }
 928
 929    void QSort3(int loSt, int hiSt, int dSt)
 930    {
 931      int unLo, unHi, ltLo, gtHi, med, n, m;
 932      int lo, hi, d;
 933
 0934      StackElement[] stack = new StackElement[QSORT_STACK_SIZE];
 935
 0936      int sp = 0;
 937
 0938      stack[sp].ll = loSt;
 0939      stack[sp].hh = hiSt;
 0940      stack[sp].dd = dSt;
 0941      sp++;
 942
 0943       while (sp > 0) {
 0944         if (sp >= QSORT_STACK_SIZE) {
 0945          Panic();
 946        }
 947
 0948        sp--;
 0949        lo = stack[sp].ll;
 0950        hi = stack[sp].hh;
 0951        d = stack[sp].dd;
 952
 0953         if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) {
 0954          SimpleSort(lo, hi, d);
 0955           if (workDone > workLimit && firstAttempt) {
 0956            return;
 957          }
 958          continue;
 959        }
 960
 0961        med = Med3(block[zptr[lo] + d + 1],
 0962               block[zptr[hi] + d + 1],
 0963               block[zptr[(lo + hi) >> 1] + d + 1]);
 964
 0965        unLo = ltLo = lo;
 0966        unHi = gtHi = hi;
 967
 0968        while (true) {
 0969          while (true) {
 0970             if (unLo > unHi) {
 971              break;
 972            }
 0973            n = ((int)block[zptr[unLo] + d + 1]) - med;
 0974             if (n == 0) {
 0975              int temp = zptr[unLo];
 0976              zptr[unLo] = zptr[ltLo];
 0977              zptr[ltLo] = temp;
 0978              ltLo++;
 0979              unLo++;
 0980              continue;
 981            }
 0982             if (n > 0) {
 983              break;
 984            }
 0985            unLo++;
 986          }
 987
 0988          while (true) {
 0989             if (unLo > unHi) {
 990              break;
 991            }
 0992            n = ((int)block[zptr[unHi] + d + 1]) - med;
 0993             if (n == 0) {
 0994              int temp = zptr[unHi];
 0995              zptr[unHi] = zptr[gtHi];
 0996              zptr[gtHi] = temp;
 0997              gtHi--;
 0998              unHi--;
 0999              continue;
 1000            }
 01001             if (n < 0) {
 1002              break;
 1003            }
 01004            unHi--;
 1005          }
 1006
 01007           if (unLo > unHi) {
 1008            break;
 1009          }
 1010
 1011          {
 01012            int temp = zptr[unLo];
 01013            zptr[unLo] = zptr[unHi];
 01014            zptr[unHi] = temp;
 01015            unLo++;
 01016            unHi--;
 1017          }
 1018        }
 1019
 01020         if (gtHi < ltLo) {
 01021          stack[sp].ll = lo;
 01022          stack[sp].hh = hi;
 01023          stack[sp].dd = d + 1;
 01024          sp++;
 01025          continue;
 1026        }
 1027
 01028        n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo);
 01029        Vswap(lo, unLo - n, n);
 01030        m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi);
 01031        Vswap(unLo, hi - m + 1, m);
 1032
 01033        n = lo + unLo - ltLo - 1;
 01034        m = hi - (gtHi - unHi) + 1;
 1035
 01036        stack[sp].ll = lo;
 01037        stack[sp].hh = n;
 01038        stack[sp].dd = d;
 01039        sp++;
 1040
 01041        stack[sp].ll = n + 1;
 01042        stack[sp].hh = m - 1;
 01043        stack[sp].dd = d + 1;
 01044        sp++;
 1045
 01046        stack[sp].ll = m;
 01047        stack[sp].hh = hi;
 01048        stack[sp].dd = d;
 01049        sp++;
 1050      }
 01051    }
 1052
 1053    void MainSort()
 1054    {
 1055      int i, j, ss, sb;
 01056      int[] runningOrder = new int[256];
 01057      int[] copy = new int[256];
 01058      bool[] bigDone = new bool[256];
 1059      int c1, c2;
 1060      int numQSorted;
 1061
 1062      /*--
 1063      In the various block-sized structures, live data runs
 1064      from 0 to last+NUM_OVERSHOOT_BYTES inclusive.  First,
 1065      set up the overshoot area for block.
 1066      --*/
 1067
 1068      //   if (verbosity >= 4) fprintf ( stderr, "        sort initialise ...\n" );
 01069       for (i = 0; i < BZip2Constants.OvershootBytes; i++) {
 01070        block[last + i + 2] = block[(i % (last + 1)) + 1];
 1071      }
 01072       for (i = 0; i <= last + BZip2Constants.OvershootBytes; i++) {
 01073        quadrant[i] = 0;
 1074      }
 1075
 01076      block[0] = (byte)(block[last + 1]);
 1077
 01078       if (last < 4000) {
 1079        /*--
 1080        Use simpleSort(), since the full sorting mechanism
 1081        has quite a large constant overhead.
 1082        --*/
 01083         for (i = 0; i <= last; i++) {
 01084          zptr[i] = i;
 1085        }
 01086        firstAttempt = false;
 01087        workDone = workLimit = 0;
 01088        SimpleSort(0, last, 0);
 01089      } else {
 01090        numQSorted = 0;
 01091         for (i = 0; i <= 255; i++) {
 01092          bigDone[i] = false;
 1093        }
 01094         for (i = 0; i <= 65536; i++) {
 01095          ftab[i] = 0;
 1096        }
 1097
 01098        c1 = block[0];
 01099         for (i = 0; i <= last; i++) {
 01100          c2 = block[i + 1];
 01101          ftab[(c1 << 8) + c2]++;
 01102          c1 = c2;
 1103        }
 1104
 01105         for (i = 1; i <= 65536; i++) {
 01106          ftab[i] += ftab[i - 1];
 1107        }
 1108
 01109        c1 = block[1];
 01110         for (i = 0; i < last; i++) {
 01111          c2 = block[i + 2];
 01112          j = (c1 << 8) + c2;
 01113          c1 = c2;
 01114          ftab[j]--;
 01115          zptr[ftab[j]] = i;
 1116        }
 1117
 01118        j = ((block[last + 1]) << 8) + (block[1]);
 01119        ftab[j]--;
 01120        zptr[ftab[j]] = last;
 1121
 1122        /*--
 1123        Now ftab contains the first loc of every small bucket.
 1124        Calculate the running order, from smallest to largest
 1125        big bucket.
 1126        --*/
 1127
 01128         for (i = 0; i <= 255; i++) {
 01129          runningOrder[i] = i;
 1130        }
 1131
 1132        int vv;
 01133        int h = 1;
 1134        do {
 01135          h = 3 * h + 1;
 01136         } while (h <= 256);
 1137        do {
 01138          h = h / 3;
 01139           for (i = h; i <= 255; i++) {
 01140            vv = runningOrder[i];
 01141            j = i;
 01142             while ((ftab[((runningOrder[j - h]) + 1) << 8] - ftab[(runningOrder[j - h]) << 8]) > (ftab[((vv) + 1) << 8] 
 01143              runningOrder[j] = runningOrder[j - h];
 01144              j = j - h;
 01145               if (j <= (h - 1)) {
 1146                break;
 1147              }
 1148            }
 01149            runningOrder[j] = vv;
 1150          }
 01151         } while (h != 1);
 1152
 1153        /*--
 1154        The main sorting loop.
 1155        --*/
 01156         for (i = 0; i <= 255; i++) {
 1157
 1158          /*--
 1159          Process big buckets, starting with the least full.
 1160          --*/
 01161          ss = runningOrder[i];
 1162
 1163          /*--
 1164          Complete the big bucket [ss] by quicksorting
 1165          any unsorted small buckets [ss, j].  Hopefully
 1166          previous pointer-scanning phases have already
 1167          completed many of the small buckets [ss, j], so
 1168          we don't have to sort them at all.
 1169          --*/
 01170           for (j = 0; j <= 255; j++) {
 01171            sb = (ss << 8) + j;
 01172             if (!((ftab[sb] & SETMASK) == SETMASK)) {
 01173              int lo = ftab[sb] & CLEARMASK;
 01174              int hi = (ftab[sb + 1] & CLEARMASK) - 1;
 01175               if (hi > lo) {
 01176                QSort3(lo, hi, 2);
 01177                numQSorted += (hi - lo + 1);
 01178                 if (workDone > workLimit && firstAttempt) {
 01179                  return;
 1180                }
 1181              }
 01182              ftab[sb] |= SETMASK;
 1183            }
 1184          }
 1185
 1186          /*--
 1187          The ss big bucket is now done.  Record this fact,
 1188          and update the quadrant descriptors.  Remember to
 1189          update quadrants in the overshoot area too, if
 1190          necessary.  The "if (i < 255)" test merely skips
 1191          this updating for the last bucket processed, since
 1192          updating for the last bucket is pointless.
 1193          --*/
 01194          bigDone[ss] = true;
 1195
 01196           if (i < 255) {
 01197            int bbStart = ftab[ss << 8] & CLEARMASK;
 01198            int bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart;
 01199            int shifts = 0;
 1200
 01201             while ((bbSize >> shifts) > 65534) {
 01202              shifts++;
 1203            }
 1204
 01205             for (j = 0; j < bbSize; j++) {
 01206              int a2update = zptr[bbStart + j];
 01207              int qVal = (j >> shifts);
 01208              quadrant[a2update] = qVal;
 01209               if (a2update < BZip2Constants.OvershootBytes) {
 01210                quadrant[a2update + last + 1] = qVal;
 1211              }
 1212            }
 1213
 01214             if (!(((bbSize - 1) >> shifts) <= 65535)) {
 01215              Panic();
 1216            }
 1217          }
 1218
 1219          /*--
 1220          Now scan this big bucket so as to synthesise the
 1221          sorted order for small buckets [t, ss] for all t != ss.
 1222          --*/
 01223           for (j = 0; j <= 255; j++) {
 01224            copy[j] = ftab[(j << 8) + ss] & CLEARMASK;
 1225          }
 1226
 01227           for (j = ftab[ss << 8] & CLEARMASK; j < (ftab[(ss + 1) << 8] & CLEARMASK); j++) {
 01228            c1 = block[zptr[j]];
 01229             if (!bigDone[c1]) {
 01230              zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1;
 01231              copy[c1]++;
 1232            }
 1233          }
 1234
 01235           for (j = 0; j <= 255; j++) {
 01236            ftab[(j << 8) + ss] |= SETMASK;
 1237          }
 1238        }
 1239      }
 01240    }
 1241
 1242    void RandomiseBlock()
 1243    {
 1244      int i;
 01245      int rNToGo = 0;
 01246      int rTPos = 0;
 01247       for (i = 0; i < 256; i++) {
 01248        inUse[i] = false;
 1249      }
 1250
 01251       for (i = 0; i <= last; i++) {
 01252         if (rNToGo == 0) {
 01253          rNToGo = (int)BZip2Constants.RandomNumbers[rTPos];
 01254          rTPos++;
 01255           if (rTPos == 512) {
 01256            rTPos = 0;
 1257          }
 1258        }
 01259        rNToGo--;
 01260         block[i + 1] ^= (byte)((rNToGo == 1) ? 1 : 0);
 1261        // handle 16 bit signed numbers
 01262        block[i + 1] &= 0xFF;
 1263
 01264        inUse[block[i + 1]] = true;
 1265      }
 01266    }
 1267
 1268    void DoReversibleTransformation()
 1269    {
 01270      workLimit = workFactor * last;
 01271      workDone = 0;
 01272      blockRandomised = false;
 01273      firstAttempt = true;
 1274
 01275      MainSort();
 1276
 01277       if (workDone > workLimit && firstAttempt) {
 01278        RandomiseBlock();
 01279        workLimit = workDone = 0;
 01280        blockRandomised = true;
 01281        firstAttempt = false;
 01282        MainSort();
 1283      }
 1284
 01285      origPtr = -1;
 01286       for (int i = 0; i <= last; i++) {
 01287         if (zptr[i] == 0) {
 01288          origPtr = i;
 01289          break;
 1290        }
 1291      }
 1292
 01293       if (origPtr == -1) {
 01294        Panic();
 1295      }
 01296    }
 1297
 1298    bool FullGtU(int i1, int i2)
 1299    {
 1300      int k;
 1301      byte c1, c2;
 1302      int s1, s2;
 1303
 01304      c1 = block[i1 + 1];
 01305      c2 = block[i2 + 1];
 01306       if (c1 != c2) {
 01307        return c1 > c2;
 1308      }
 01309      i1++;
 01310      i2++;
 1311
 01312      c1 = block[i1 + 1];
 01313      c2 = block[i2 + 1];
 01314       if (c1 != c2) {
 01315        return c1 > c2;
 1316      }
 01317      i1++;
 01318      i2++;
 1319
 01320      c1 = block[i1 + 1];
 01321      c2 = block[i2 + 1];
 01322       if (c1 != c2) {
 01323        return c1 > c2;
 1324      }
 01325      i1++;
 01326      i2++;
 1327
 01328      c1 = block[i1 + 1];
 01329      c2 = block[i2 + 1];
 01330       if (c1 != c2) {
 01331        return c1 > c2;
 1332      }
 01333      i1++;
 01334      i2++;
 1335
 01336      c1 = block[i1 + 1];
 01337      c2 = block[i2 + 1];
 01338       if (c1 != c2) {
 01339        return c1 > c2;
 1340      }
 01341      i1++;
 01342      i2++;
 1343
 01344      c1 = block[i1 + 1];
 01345      c2 = block[i2 + 1];
 01346       if (c1 != c2) {
 01347        return c1 > c2;
 1348      }
 01349      i1++;
 01350      i2++;
 1351
 01352      k = last + 1;
 1353
 1354      do {
 01355        c1 = block[i1 + 1];
 01356        c2 = block[i2 + 1];
 01357         if (c1 != c2) {
 01358          return c1 > c2;
 1359        }
 01360        s1 = quadrant[i1];
 01361        s2 = quadrant[i2];
 01362         if (s1 != s2) {
 01363          return s1 > s2;
 1364        }
 01365        i1++;
 01366        i2++;
 1367
 01368        c1 = block[i1 + 1];
 01369        c2 = block[i2 + 1];
 01370         if (c1 != c2) {
 01371          return c1 > c2;
 1372        }
 01373        s1 = quadrant[i1];
 01374        s2 = quadrant[i2];
 01375         if (s1 != s2) {
 01376          return s1 > s2;
 1377        }
 01378        i1++;
 01379        i2++;
 1380
 01381        c1 = block[i1 + 1];
 01382        c2 = block[i2 + 1];
 01383         if (c1 != c2) {
 01384          return c1 > c2;
 1385        }
 01386        s1 = quadrant[i1];
 01387        s2 = quadrant[i2];
 01388         if (s1 != s2) {
 01389          return s1 > s2;
 1390        }
 01391        i1++;
 01392        i2++;
 1393
 01394        c1 = block[i1 + 1];
 01395        c2 = block[i2 + 1];
 01396         if (c1 != c2) {
 01397          return c1 > c2;
 1398        }
 01399        s1 = quadrant[i1];
 01400        s2 = quadrant[i2];
 01401         if (s1 != s2) {
 01402          return s1 > s2;
 1403        }
 01404        i1++;
 01405        i2++;
 1406
 01407         if (i1 > last) {
 01408          i1 -= last;
 01409          i1--;
 1410        }
 01411         if (i2 > last) {
 01412          i2 -= last;
 01413          i2--;
 1414        }
 1415
 01416        k -= 4;
 01417        ++workDone;
 01418       } while (k >= 0);
 1419
 01420      return false;
 1421    }
 1422
 1423    void AllocateCompressStructures()
 1424    {
 11425      int n = BZip2Constants.BaseBlockSize * blockSize100k;
 11426      block = new byte[(n + 1 + BZip2Constants.OvershootBytes)];
 11427      quadrant = new int[(n + BZip2Constants.OvershootBytes)];
 11428      zptr = new int[n];
 11429      ftab = new int[65537];
 1430
 11431       if (block == null || quadrant == null || zptr == null || ftab == null) {
 1432        //    int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;
 1433        //    compressOutOfMemory ( totalDraw, n );
 1434      }
 1435
 1436      /*
 1437      The back end needs a place to store the MTF values
 1438      whilst it calculates the coding tables.  We could
 1439      put them in the zptr array.  However, these values
 1440      will fit in a short, so we overlay szptr at the
 1441      start of zptr, in the hope of reducing the number
 1442      of cache misses induced by the multiple traversals
 1443      of the MTF values when calculating coding tables.
 1444      Seems to improve compression speed by about 1%.
 1445      */
 1446      //  szptr = zptr;
 1447
 1448
 11449      szptr = new short[2 * n];
 11450    }
 1451
 1452    void GenerateMTFValues()
 1453    {
 01454      char[] yy = new char[256];
 1455      int i, j;
 1456      char tmp;
 1457      char tmp2;
 1458      int zPend;
 1459      int wr;
 1460      int EOB;
 1461
 01462      MakeMaps();
 01463      EOB = nInUse + 1;
 1464
 01465       for (i = 0; i <= EOB; i++) {
 01466        mtfFreq[i] = 0;
 1467      }
 1468
 01469      wr = 0;
 01470      zPend = 0;
 01471       for (i = 0; i < nInUse; i++) {
 01472        yy[i] = (char)i;
 1473      }
 1474
 1475
 01476       for (i = 0; i <= last; i++) {
 1477        char ll_i;
 1478
 01479        ll_i = unseqToSeq[block[zptr[i]]];
 1480
 01481        j = 0;
 01482        tmp = yy[j];
 01483         while (ll_i != tmp) {
 01484          j++;
 01485          tmp2 = tmp;
 01486          tmp = yy[j];
 01487          yy[j] = tmp2;
 1488        }
 01489        yy[0] = tmp;
 1490
 01491         if (j == 0) {
 01492          zPend++;
 01493        } else {
 01494           if (zPend > 0) {
 01495            zPend--;
 01496            while (true) {
 01497               switch (zPend % 2) {
 1498                case 0:
 01499                  szptr[wr] = (short)BZip2Constants.RunA;
 01500                  wr++;
 01501                  mtfFreq[BZip2Constants.RunA]++;
 01502                  break;
 1503                case 1:
 01504                  szptr[wr] = (short)BZip2Constants.RunB;
 01505                  wr++;
 01506                  mtfFreq[BZip2Constants.RunB]++;
 1507                  break;
 1508              }
 01509               if (zPend < 2) {
 1510                break;
 1511              }
 01512              zPend = (zPend - 2) / 2;
 1513            }
 01514            zPend = 0;
 1515          }
 01516          szptr[wr] = (short)(j + 1);
 01517          wr++;
 01518          mtfFreq[j + 1]++;
 1519        }
 1520      }
 1521
 01522       if (zPend > 0) {
 01523        zPend--;
 01524        while (true) {
 01525           switch (zPend % 2) {
 1526            case 0:
 01527              szptr[wr] = (short)BZip2Constants.RunA;
 01528              wr++;
 01529              mtfFreq[BZip2Constants.RunA]++;
 01530              break;
 1531            case 1:
 01532              szptr[wr] = (short)BZip2Constants.RunB;
 01533              wr++;
 01534              mtfFreq[BZip2Constants.RunB]++;
 1535              break;
 1536          }
 01537           if (zPend < 2) {
 1538            break;
 1539          }
 01540          zPend = (zPend - 2) / 2;
 1541        }
 1542      }
 1543
 01544      szptr[wr] = (short)EOB;
 01545      wr++;
 01546      mtfFreq[EOB]++;
 1547
 01548      nMTF = wr;
 01549    }
 1550
 1551    static void Panic()
 1552    {
 01553      throw new BZip2Exception("BZip2 output stream panic");
 1554    }
 1555
 1556    static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen)
 1557    {
 1558      /*--
 1559      Nodes and heap entries run from 1.  Entry 0
 1560      for both the heap and nodes is a sentinel.
 1561      --*/
 1562      int nNodes, nHeap, n1, n2, j, k;
 1563      bool tooLong;
 1564
 01565      int[] heap = new int[BZip2Constants.MaximumAlphaSize + 2];
 01566      int[] weight = new int[BZip2Constants.MaximumAlphaSize * 2];
 01567      int[] parent = new int[BZip2Constants.MaximumAlphaSize * 2];
 1568
 01569       for (int i = 0; i < alphaSize; ++i) {
 01570        weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
 1571      }
 1572
 01573      while (true) {
 01574        nNodes = alphaSize;
 01575        nHeap = 0;
 1576
 01577        heap[0] = 0;
 01578        weight[0] = 0;
 01579        parent[0] = -2;
 1580
 01581         for (int i = 1; i <= alphaSize; ++i) {
 01582          parent[i] = -1;
 01583          nHeap++;
 01584          heap[nHeap] = i;
 01585          int zz = nHeap;
 01586          int tmp = heap[zz];
 01587           while (weight[tmp] < weight[heap[zz >> 1]]) {
 01588            heap[zz] = heap[zz >> 1];
 01589            zz >>= 1;
 1590          }
 01591          heap[zz] = tmp;
 1592        }
 01593         if (!(nHeap < (BZip2Constants.MaximumAlphaSize + 2))) {
 01594          Panic();
 1595        }
 1596
 01597         while (nHeap > 1) {
 01598          n1 = heap[1];
 01599          heap[1] = heap[nHeap];
 01600          nHeap--;
 01601          int zz = 1;
 01602          int yy = 0;
 01603          int tmp = heap[zz];
 01604          while (true) {
 01605            yy = zz << 1;
 01606             if (yy > nHeap) {
 1607              break;
 1608            }
 01609             if (yy < nHeap && weight[heap[yy + 1]] < weight[heap[yy]]) {
 01610              yy++;
 1611            }
 01612             if (weight[tmp] < weight[heap[yy]]) {
 1613              break;
 1614            }
 1615
 01616            heap[zz] = heap[yy];
 01617            zz = yy;
 1618          }
 01619          heap[zz] = tmp;
 01620          n2 = heap[1];
 01621          heap[1] = heap[nHeap];
 01622          nHeap--;
 1623
 01624          zz = 1;
 01625          yy = 0;
 01626          tmp = heap[zz];
 01627          while (true) {
 01628            yy = zz << 1;
 01629             if (yy > nHeap) {
 1630              break;
 1631            }
 01632             if (yy < nHeap && weight[heap[yy + 1]] < weight[heap[yy]]) {
 01633              yy++;
 1634            }
 01635             if (weight[tmp] < weight[heap[yy]]) {
 1636              break;
 1637            }
 01638            heap[zz] = heap[yy];
 01639            zz = yy;
 1640          }
 01641          heap[zz] = tmp;
 01642          nNodes++;
 01643          parent[n1] = parent[n2] = nNodes;
 1644
 01645          weight[nNodes] = (int)((weight[n1] & 0xffffff00) + (weight[n2] & 0xffffff00)) |
 01646            (int)(1 + (((weight[n1] & 0x000000ff) > (weight[n2] & 0x000000ff)) ? (weight[n1] & 0x000000ff) : (weight[n2]
 1647
 01648          parent[nNodes] = -1;
 01649          nHeap++;
 01650          heap[nHeap] = nNodes;
 1651
 01652          zz = nHeap;
 01653          tmp = heap[zz];
 01654           while (weight[tmp] < weight[heap[zz >> 1]]) {
 01655            heap[zz] = heap[zz >> 1];
 01656            zz >>= 1;
 1657          }
 01658          heap[zz] = tmp;
 1659        }
 01660         if (!(nNodes < (BZip2Constants.MaximumAlphaSize * 2))) {
 01661          Panic();
 1662        }
 1663
 01664        tooLong = false;
 01665         for (int i = 1; i <= alphaSize; ++i) {
 01666          j = 0;
 01667          k = i;
 01668           while (parent[k] >= 0) {
 01669            k = parent[k];
 01670            j++;
 1671          }
 01672          len[i - 1] = (char)j;
 01673          tooLong |= j > maxLen;
 1674        }
 1675
 01676         if (!tooLong) {
 1677          break;
 1678        }
 1679
 01680         for (int i = 1; i < alphaSize; ++i) {
 01681          j = weight[i] >> 8;
 01682          j = 1 + (j / 2);
 01683          weight[i] = j << 8;
 1684        }
 1685      }
 01686    }
 1687
 1688    static void HbAssignCodes(int[] code, char[] length, int minLen, int maxLen, int alphaSize)
 1689    {
 01690      int vec = 0;
 01691       for (int n = minLen; n <= maxLen; ++n) {
 01692         for (int i = 0; i < alphaSize; ++i) {
 01693           if (length[i] == n) {
 01694            code[i] = vec;
 01695            ++vec;
 1696          }
 1697        }
 01698        vec <<= 1;
 1699      }
 01700    }
 1701
 1702    static byte Med3(byte a, byte b, byte c)
 1703    {
 1704      byte t;
 01705       if (a > b) {
 01706        t = a;
 01707        a = b;
 01708        b = t;
 1709      }
 01710       if (b > c) {
 01711        t = b;
 01712        b = c;
 01713        c = t;
 1714      }
 01715       if (a > b) {
 01716        b = a;
 1717      }
 01718      return b;
 1719    }
 1720
 1721    struct StackElement
 1722    {
 1723      public int ll;
 1724      public int hh;
 1725      public int dd;
 1726    }
 1727
 1728    #region Instance Fields
 11729    bool isStreamOwner = true;
 1730
 1731    /*--
 1732    index of the last char in the block, so
 1733    the block size == last + 1.
 1734    --*/
 1735    int last;
 1736
 1737    /*--
 1738    index in zptr[] of original string after sorting.
 1739    --*/
 1740    int origPtr;
 1741
 1742    /*--
 1743    always: in the range 0 .. 9.
 1744    The current block size is 100000 * this number.
 1745    --*/
 1746    int blockSize100k;
 1747
 1748    bool blockRandomised;
 1749
 1750    int bytesOut;
 1751    int bsBuff;
 1752    int bsLive;
 11753    IChecksum mCrc = new BZip2Crc();
 1754
 11755    bool[] inUse = new bool[256];
 1756    int nInUse;
 1757
 11758    char[] seqToUnseq = new char[256];
 11759    char[] unseqToSeq = new char[256];
 1760
 11761    char[] selector = new char[BZip2Constants.MaximumSelectors];
 11762    char[] selectorMtf = new char[BZip2Constants.MaximumSelectors];
 1763
 1764    byte[] block;
 1765    int[] quadrant;
 1766    int[] zptr;
 1767    short[] szptr;
 1768    int[] ftab;
 1769
 1770    int nMTF;
 1771
 11772    int[] mtfFreq = new int[BZip2Constants.MaximumAlphaSize];
 1773
 1774    /*
 1775    * Used when sorting.  If too many long comparisons
 1776    * happen, we stop sorting, randomise the block
 1777    * slightly, and try again.
 1778    */
 1779    int workFactor;
 1780    int workDone;
 1781    int workLimit;
 1782    bool firstAttempt;
 1783    int nBlocksRandomised;
 1784
 11785    int currentChar = -1;
 1786    int runLength;
 1787    uint blockCRC, combinedCRC;
 1788    int allowableBlockSize;
 1789    Stream baseStream;
 1790    bool disposed_;
 1791    #endregion
 1792  }
 1793}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_BaseArchiveStorage.htm b/docs/opencover/ICSharpCode.SharpZipLib_BaseArchiveStorage.htm new file mode 100644 index 000000000..fc090fd6d --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_BaseArchiveStorage.htm @@ -0,0 +1,4304 @@ + + + + +ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs
Covered lines:4
Uncovered lines:0
Coverable lines:4
Total lines:4263
Line coverage:100%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.IO;
 4using System.Text;
 5using System.Globalization;
 6using System.Security.Cryptography;
 7using ICSharpCode.SharpZipLib.Encryption;
 8using ICSharpCode.SharpZipLib.Core;
 9using ICSharpCode.SharpZipLib.Checksum;
 10using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 11using ICSharpCode.SharpZipLib.Zip.Compression;
 12
 13namespace ICSharpCode.SharpZipLib.Zip
 14{
 15  #region Keys Required Event Args
 16  /// <summary>
 17  /// Arguments used with KeysRequiredEvent
 18  /// </summary>
 19  public class KeysRequiredEventArgs : EventArgs
 20  {
 21    #region Constructors
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 24    /// </summary>
 25    /// <param name="name">The name of the file for which keys are required.</param>
 26    public KeysRequiredEventArgs(string name)
 27    {
 28      fileName = name;
 29    }
 30
 31    /// <summary>
 32    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 33    /// </summary>
 34    /// <param name="name">The name of the file for which keys are required.</param>
 35    /// <param name="keyValue">The current key value.</param>
 36    public KeysRequiredEventArgs(string name, byte[] keyValue)
 37    {
 38      fileName = name;
 39      key = keyValue;
 40    }
 41
 42    #endregion
 43    #region Properties
 44    /// <summary>
 45    /// Gets the name of the file for which keys are required.
 46    /// </summary>
 47    public string FileName {
 48      get { return fileName; }
 49    }
 50
 51    /// <summary>
 52    /// Gets or sets the key value
 53    /// </summary>
 54    public byte[] Key {
 55      get { return key; }
 56      set { key = value; }
 57    }
 58    #endregion
 59
 60    #region Instance Fields
 61    string fileName;
 62    byte[] key;
 63    #endregion
 64  }
 65  #endregion
 66
 67  #region Test Definitions
 68  /// <summary>
 69  /// The strategy to apply to testing.
 70  /// </summary>
 71  public enum TestStrategy
 72  {
 73    /// <summary>
 74    /// Find the first error only.
 75    /// </summary>
 76    FindFirstError,
 77    /// <summary>
 78    /// Find all possible errors.
 79    /// </summary>
 80    FindAllErrors,
 81  }
 82
 83  /// <summary>
 84  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.
 85  /// </summary>
 86  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 87  public enum TestOperation
 88  {
 89    /// <summary>
 90    /// Setting up testing.
 91    /// </summary>
 92    Initialising,
 93
 94    /// <summary>
 95    /// Testing an individual entries header
 96    /// </summary>
 97    EntryHeader,
 98
 99    /// <summary>
 100    /// Testing an individual entries data
 101    /// </summary>
 102    EntryData,
 103
 104    /// <summary>
 105    /// Testing an individual entry has completed.
 106    /// </summary>
 107    EntryComplete,
 108
 109    /// <summary>
 110    /// Running miscellaneous tests
 111    /// </summary>
 112    MiscellaneousTests,
 113
 114    /// <summary>
 115    /// Testing is complete
 116    /// </summary>
 117    Complete,
 118  }
 119
 120  /// <summary>
 121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.
 122  /// </summary>
 123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 124  public class TestStatus
 125  {
 126    #region Constructors
 127    /// <summary>
 128    /// Initialise a new instance of <see cref="TestStatus"/>
 129    /// </summary>
 130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>
 131    public TestStatus(ZipFile file)
 132    {
 133      file_ = file;
 134    }
 135    #endregion
 136
 137    #region Properties
 138
 139    /// <summary>
 140    /// Get the current <see cref="TestOperation"/> in progress.
 141    /// </summary>
 142    public TestOperation Operation {
 143      get { return operation_; }
 144    }
 145
 146    /// <summary>
 147    /// Get the <see cref="ZipFile"/> this status is applicable to.
 148    /// </summary>
 149    public ZipFile File {
 150      get { return file_; }
 151    }
 152
 153    /// <summary>
 154    /// Get the current/last entry tested.
 155    /// </summary>
 156    public ZipEntry Entry {
 157      get { return entry_; }
 158    }
 159
 160    /// <summary>
 161    /// Get the number of errors detected so far.
 162    /// </summary>
 163    public int ErrorCount {
 164      get { return errorCount_; }
 165    }
 166
 167    /// <summary>
 168    /// Get the number of bytes tested so far for the current entry.
 169    /// </summary>
 170    public long BytesTested {
 171      get { return bytesTested_; }
 172    }
 173
 174    /// <summary>
 175    /// Get a value indicating wether the last entry test was valid.
 176    /// </summary>
 177    public bool EntryValid {
 178      get { return entryValid_; }
 179    }
 180    #endregion
 181
 182    #region Internal API
 183    internal void AddError()
 184    {
 185      errorCount_++;
 186      entryValid_ = false;
 187    }
 188
 189    internal void SetOperation(TestOperation operation)
 190    {
 191      operation_ = operation;
 192    }
 193
 194    internal void SetEntry(ZipEntry entry)
 195    {
 196      entry_ = entry;
 197      entryValid_ = true;
 198      bytesTested_ = 0;
 199    }
 200
 201    internal void SetBytesTested(long value)
 202    {
 203      bytesTested_ = value;
 204    }
 205    #endregion
 206
 207    #region Instance Fields
 208    ZipFile file_;
 209    ZipEntry entry_;
 210    bool entryValid_;
 211    int errorCount_;
 212    long bytesTested_;
 213    TestOperation operation_;
 214    #endregion
 215  }
 216
 217  /// <summary>
 218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if
 219  /// </summary>
 220  /// <remarks>If the message is non-null an error has occured.  If the message is null
 221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>
 222  public delegate void ZipTestResultHandler(TestStatus status, string message);
 223  #endregion
 224
 225  #region Update Definitions
 226  /// <summary>
 227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.
 228  /// </summary>
 229  public enum FileUpdateMode
 230  {
 231    /// <summary>
 232    /// Perform all updates on temporary files ensuring that the original file is saved.
 233    /// </summary>
 234    Safe,
 235    /// <summary>
 236    /// Update the archive directly, which is faster but less safe.
 237    /// </summary>
 238    Direct,
 239  }
 240  #endregion
 241
 242  #region ZipFile Class
 243  /// <summary>
 244  /// This class represents a Zip archive.  You can ask for the contained
 245  /// entries, or get an input stream for a file entry.  The entry is
 246  /// automatically decompressed.
 247  ///
 248  /// You can also update the archive adding or deleting entries.
 249  ///
 250  /// This class is thread safe for input:  You can open input streams for arbitrary
 251  /// entries in different threads.
 252  /// <br/>
 253  /// <br/>Author of the original java version : Jochen Hoenicke
 254  /// </summary>
 255  /// <example>
 256  /// <code>
 257  /// using System;
 258  /// using System.Text;
 259  /// using System.Collections;
 260  /// using System.IO;
 261  ///
 262  /// using ICSharpCode.SharpZipLib.Zip;
 263  ///
 264  /// class MainClass
 265  /// {
 266  ///   static public void Main(string[] args)
 267  ///   {
 268  ///     using (ZipFile zFile = new ZipFile(args[0])) {
 269  ///       Console.WriteLine("Listing of : " + zFile.Name);
 270  ///       Console.WriteLine("");
 271  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");
 272  ///       Console.WriteLine("--------  --------  --------  ------  ---------");
 273  ///       foreach (ZipEntry e in zFile) {
 274  ///         if ( e.IsFile ) {
 275  ///           DateTime d = e.DateTime;
 276  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,
 277  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),
 278  ///             e.Name);
 279  ///         }
 280  ///       }
 281  ///     }
 282  ///   }
 283  /// }
 284  /// </code>
 285  /// </example>
 286  public class ZipFile : IEnumerable, IDisposable
 287  {
 288    #region KeyHandling
 289
 290    /// <summary>
 291    /// Delegate for handling keys/password setting during compresion/decompression.
 292    /// </summary>
 293    public delegate void KeysRequiredEventHandler(
 294      object sender,
 295      KeysRequiredEventArgs e
 296    );
 297
 298    /// <summary>
 299    /// Event handler for handling encryption keys.
 300    /// </summary>
 301    public KeysRequiredEventHandler KeysRequired;
 302
 303    /// <summary>
 304    /// Handles getting of encryption keys when required.
 305    /// </summary>
 306    /// <param name="fileName">The file for which encryption keys are required.</param>
 307    void OnKeysRequired(string fileName)
 308    {
 309      if (KeysRequired != null) {
 310        var krea = new KeysRequiredEventArgs(fileName, key);
 311        KeysRequired(this, krea);
 312        key = krea.Key;
 313      }
 314    }
 315
 316    /// <summary>
 317    /// Get/set the encryption key value.
 318    /// </summary>
 319    byte[] Key {
 320      get { return key; }
 321      set { key = value; }
 322    }
 323
 324    /// <summary>
 325    /// Password to be used for encrypting/decrypting files.
 326    /// </summary>
 327    /// <remarks>Set to null if no password is required.</remarks>
 328    public string Password {
 329      set {
 330        if (string.IsNullOrEmpty(value)) {
 331          key = null;
 332        } else {
 333          rawPassword_ = value;
 334          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));
 335        }
 336      }
 337    }
 338
 339    /// <summary>
 340    /// Get a value indicating wether encryption keys are currently available.
 341    /// </summary>
 342    bool HaveKeys {
 343      get { return key != null; }
 344    }
 345    #endregion
 346
 347    #region Constructors
 348    /// <summary>
 349    /// Opens a Zip file with the given name for reading.
 350    /// </summary>
 351    /// <param name="name">The name of the file to open.</param>
 352    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>
 353    /// <exception cref="IOException">
 354    /// An i/o error occurs
 355    /// </exception>
 356    /// <exception cref="ZipException">
 357    /// The file doesn't contain a valid zip archive.
 358    /// </exception>
 359    public ZipFile(string name)
 360    {
 361      if (name == null) {
 362        throw new ArgumentNullException(nameof(name));
 363      }
 364
 365      name_ = name;
 366
 367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 368      isStreamOwner = true;
 369
 370      try {
 371        ReadEntries();
 372      } catch {
 373        DisposeInternal(true);
 374        throw;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Opens a Zip file reading the given <see cref="FileStream"/>.
 380    /// </summary>
 381    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>
 382    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>
 383    /// <exception cref="IOException">
 384    /// An i/o error occurs.
 385    /// </exception>
 386    /// <exception cref="ZipException">
 387    /// The file doesn't contain a valid zip archive.
 388    /// </exception>
 389    public ZipFile(FileStream file)
 390    {
 391      if (file == null) {
 392        throw new ArgumentNullException(nameof(file));
 393      }
 394
 395      if (!file.CanSeek) {
 396        throw new ArgumentException("Stream is not seekable", nameof(file));
 397      }
 398
 399      baseStream_ = file;
 400      name_ = file.Name;
 401      isStreamOwner = true;
 402
 403      try {
 404        ReadEntries();
 405      } catch {
 406        DisposeInternal(true);
 407        throw;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Opens a Zip file reading the given <see cref="Stream"/>.
 413    /// </summary>
 414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
 415    /// <exception cref="IOException">
 416    /// An i/o error occurs
 417    /// </exception>
 418    /// <exception cref="ZipException">
 419    /// The stream doesn't contain a valid zip archive.<br/>
 420    /// </exception>
 421    /// <exception cref="ArgumentException">
 422    /// The <see cref="Stream">stream</see> doesnt support seeking.
 423    /// </exception>
 424    /// <exception cref="ArgumentNullException">
 425    /// The <see cref="Stream">stream</see> argument is null.
 426    /// </exception>
 427    public ZipFile(Stream stream)
 428    {
 429      if (stream == null) {
 430        throw new ArgumentNullException(nameof(stream));
 431      }
 432
 433      if (!stream.CanSeek) {
 434        throw new ArgumentException("Stream is not seekable", nameof(stream));
 435      }
 436
 437      baseStream_ = stream;
 438      isStreamOwner = true;
 439
 440      if (baseStream_.Length > 0) {
 441        try {
 442          ReadEntries();
 443        } catch {
 444          DisposeInternal(true);
 445          throw;
 446        }
 447      } else {
 448        entries_ = new ZipEntry[0];
 449        isNewArchive_ = true;
 450      }
 451    }
 452
 453    /// <summary>
 454    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
 455    /// </summary>
 456    internal ZipFile()
 457    {
 458      entries_ = new ZipEntry[0];
 459      isNewArchive_ = true;
 460    }
 461
 462    #endregion
 463
 464    #region Destructors and Closing
 465    /// <summary>
 466    /// Finalize this instance.
 467    /// </summary>
 468    ~ZipFile()
 469    {
 470      Dispose(false);
 471    }
 472
 473    /// <summary>
 474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying
 475    /// Once closed, no further instance methods should be called.
 476    /// </summary>
 477    /// <exception cref="System.IO.IOException">
 478    /// An i/o error occurs.
 479    /// </exception>
 480    public void Close()
 481    {
 482      DisposeInternal(true);
 483      GC.SuppressFinalize(this);
 484    }
 485
 486    #endregion
 487
 488    #region Creators
 489    /// <summary>
 490    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.
 491    /// </summary>
 492    /// <param name="fileName">The name of the archive to create.</param>
 493    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 494    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>
 495    public static ZipFile Create(string fileName)
 496    {
 497      if (fileName == null) {
 498        throw new ArgumentNullException(nameof(fileName));
 499      }
 500
 501      FileStream fs = File.Create(fileName);
 502
 503      var result = new ZipFile();
 504      result.name_ = fileName;
 505      result.baseStream_ = fs;
 506      result.isStreamOwner = true;
 507      return result;
 508    }
 509
 510    /// <summary>
 511    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.
 512    /// </summary>
 513    /// <param name="outStream">The stream providing data storage.</param>
 514    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 515    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>
 516    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>
 517    public static ZipFile Create(Stream outStream)
 518    {
 519      if (outStream == null) {
 520        throw new ArgumentNullException(nameof(outStream));
 521      }
 522
 523      if (!outStream.CanWrite) {
 524        throw new ArgumentException("Stream is not writeable", nameof(outStream));
 525      }
 526
 527      if (!outStream.CanSeek) {
 528        throw new ArgumentException("Stream is not seekable", nameof(outStream));
 529      }
 530
 531      var result = new ZipFile();
 532      result.baseStream_ = outStream;
 533      return result;
 534    }
 535
 536    #endregion
 537
 538    #region Properties
 539    /// <summary>
 540    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
 541    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
 542    /// </summary>
 543    /// <remarks>
 544    /// The default value is true in all cases.
 545    /// </remarks>
 546    public bool IsStreamOwner {
 547      get { return isStreamOwner; }
 548      set { isStreamOwner = value; }
 549    }
 550
 551    /// <summary>
 552    /// Get a value indicating wether
 553    /// this archive is embedded in another file or not.
 554    /// </summary>
 555    public bool IsEmbeddedArchive {
 556      // Not strictly correct in all circumstances currently
 557      get { return offsetOfFirstEntry > 0; }
 558    }
 559
 560    /// <summary>
 561    /// Get a value indicating that this archive is a new one.
 562    /// </summary>
 563    public bool IsNewArchive {
 564      get { return isNewArchive_; }
 565    }
 566
 567    /// <summary>
 568    /// Gets the comment for the zip file.
 569    /// </summary>
 570    public string ZipFileComment {
 571      get { return comment_; }
 572    }
 573
 574    /// <summary>
 575    /// Gets the name of this zip file.
 576    /// </summary>
 577    public string Name {
 578      get { return name_; }
 579    }
 580
 581    /// <summary>
 582    /// Gets the number of entries in this zip file.
 583    /// </summary>
 584    /// <exception cref="InvalidOperationException">
 585    /// The Zip file has been closed.
 586    /// </exception>
 587    [Obsolete("Use the Count property instead")]
 588    public int Size {
 589      get {
 590        return entries_.Length;
 591      }
 592    }
 593
 594    /// <summary>
 595    /// Get the number of entries contained in this <see cref="ZipFile"/>.
 596    /// </summary>
 597    public long Count {
 598      get {
 599        return entries_.Length;
 600      }
 601    }
 602
 603    /// <summary>
 604    /// Indexer property for ZipEntries
 605    /// </summary>
 606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
 607    public ZipEntry this[int index] {
 608      get {
 609        return (ZipEntry)entries_[index].Clone();
 610      }
 611    }
 612
 613    #endregion
 614
 615    #region Input Handling
 616    /// <summary>
 617    /// Gets an enumerator for the Zip entries in this Zip file.
 618    /// </summary>
 619    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>
 620    /// <exception cref="ObjectDisposedException">
 621    /// The Zip file has been closed.
 622    /// </exception>
 623    public IEnumerator GetEnumerator()
 624    {
 625      if (isDisposed_) {
 626        throw new ObjectDisposedException("ZipFile");
 627      }
 628
 629      return new ZipEntryEnumerator(entries_);
 630    }
 631
 632    /// <summary>
 633    /// Return the index of the entry with a matching name
 634    /// </summary>
 635    /// <param name="name">Entry name to find</param>
 636    /// <param name="ignoreCase">If true the comparison is case insensitive</param>
 637    /// <returns>The index position of the matching entry or -1 if not found</returns>
 638    /// <exception cref="ObjectDisposedException">
 639    /// The Zip file has been closed.
 640    /// </exception>
 641    public int FindEntry(string name, bool ignoreCase)
 642    {
 643      if (isDisposed_) {
 644        throw new ObjectDisposedException("ZipFile");
 645      }
 646
 647      // TODO: This will be slow as the next ice age for huge archives!
 648      for (int i = 0; i < entries_.Length; i++) {
 649        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {
 650          return i;
 651        }
 652      }
 653      return -1;
 654    }
 655
 656    /// <summary>
 657    /// Searches for a zip entry in this archive with the given name.
 658    /// String comparisons are case insensitive
 659    /// </summary>
 660    /// <param name="name">
 661    /// The name to find. May contain directory components separated by slashes ('/').
 662    /// </param>
 663    /// <returns>
 664    /// A clone of the zip entry, or null if no entry with that name exists.
 665    /// </returns>
 666    /// <exception cref="ObjectDisposedException">
 667    /// The Zip file has been closed.
 668    /// </exception>
 669    public ZipEntry GetEntry(string name)
 670    {
 671      if (isDisposed_) {
 672        throw new ObjectDisposedException("ZipFile");
 673      }
 674
 675      int index = FindEntry(name, true);
 676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;
 677    }
 678
 679    /// <summary>
 680    /// Gets an input stream for reading the given zip entry data in an uncompressed form.
 681    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
 682    /// </summary>
 683    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
 684    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
 685    /// <exception cref="ObjectDisposedException">
 686    /// The ZipFile has already been closed
 687    /// </exception>
 688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 689    /// The compression method for the entry is unknown
 690    /// </exception>
 691    /// <exception cref="IndexOutOfRangeException">
 692    /// The entry is not found in the ZipFile
 693    /// </exception>
 694    public Stream GetInputStream(ZipEntry entry)
 695    {
 696      if (entry == null) {
 697        throw new ArgumentNullException(nameof(entry));
 698      }
 699
 700      if (isDisposed_) {
 701        throw new ObjectDisposedException("ZipFile");
 702      }
 703
 704      long index = entry.ZipFileIndex;
 705      if ((index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name)) {
 706        index = FindEntry(entry.Name, true);
 707        if (index < 0) {
 708          throw new ZipException("Entry cannot be found");
 709        }
 710      }
 711      return GetInputStream(index);
 712    }
 713
 714    /// <summary>
 715    /// Creates an input stream reading a zip entry
 716    /// </summary>
 717    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
 718    /// <returns>
 719    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>
 720    /// </returns>
 721    /// <exception cref="ObjectDisposedException">
 722    /// The ZipFile has already been closed
 723    /// </exception>
 724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 725    /// The compression method for the entry is unknown
 726    /// </exception>
 727    /// <exception cref="IndexOutOfRangeException">
 728    /// The entry is not found in the ZipFile
 729    /// </exception>
 730    public Stream GetInputStream(long entryIndex)
 731    {
 732      if (isDisposed_) {
 733        throw new ObjectDisposedException("ZipFile");
 734      }
 735
 736      long start = LocateEntry(entries_[entryIndex]);
 737      CompressionMethod method = entries_[entryIndex].CompressionMethod;
 738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);
 739
 740      if (entries_[entryIndex].IsCrypted == true) {
 741        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);
 742        if (result == null) {
 743          throw new ZipException("Unable to decrypt this entry");
 744        }
 745      }
 746
 747      switch (method) {
 748        case CompressionMethod.Stored:
 749          // read as is.
 750          break;
 751
 752        case CompressionMethod.Deflated:
 753          // No need to worry about ownership and closing as underlying stream close does nothing.
 754          result = new InflaterInputStream(result, new Inflater(true));
 755          break;
 756
 757        default:
 758          throw new ZipException("Unsupported compression method " + method);
 759      }
 760
 761      return result;
 762    }
 763
 764    #endregion
 765
 766    #region Archive Testing
 767    /// <summary>
 768    /// Test an archive for integrity/validity
 769    /// </summary>
 770    /// <param name="testData">Perform low level data Crc check</param>
 771    /// <returns>true if all tests pass, false otherwise</returns>
 772    /// <remarks>Testing will terminate on the first error found.</remarks>
 773    public bool TestArchive(bool testData)
 774    {
 775      return TestArchive(testData, TestStrategy.FindFirstError, null);
 776    }
 777
 778    /// <summary>
 779    /// Test an archive for integrity/validity
 780    /// </summary>
 781    /// <param name="testData">Perform low level data Crc check</param>
 782    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
 783    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
 784    /// <returns>true if all tests pass, false otherwise</returns>
 785    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>
 786    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
 787    {
 788      if (isDisposed_) {
 789        throw new ObjectDisposedException("ZipFile");
 790      }
 791
 792      var status = new TestStatus(this);
 793
 794      if (resultHandler != null) {
 795        resultHandler(status, null);
 796      }
 797
 798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;
 799
 800      bool testing = true;
 801
 802      try {
 803        int entryIndex = 0;
 804
 805        while (testing && (entryIndex < Count)) {
 806          if (resultHandler != null) {
 807            status.SetEntry(this[entryIndex]);
 808            status.SetOperation(TestOperation.EntryHeader);
 809            resultHandler(status, null);
 810          }
 811
 812          try {
 813            TestLocalHeader(this[entryIndex], test);
 814          } catch (ZipException ex) {
 815            status.AddError();
 816
 817            if (resultHandler != null) {
 818              resultHandler(status,
 819                string.Format("Exception during test - '{0}'", ex.Message));
 820            }
 821
 822            testing &= strategy != TestStrategy.FindFirstError;
 823          }
 824
 825          if (testing && testData && this[entryIndex].IsFile) {
 826            if (resultHandler != null) {
 827              status.SetOperation(TestOperation.EntryData);
 828              resultHandler(status, null);
 829            }
 830
 831            var crc = new Crc32();
 832
 833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {
 834
 835              byte[] buffer = new byte[4096];
 836              long totalBytes = 0;
 837              int bytesRead;
 838              while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
 839                crc.Update(buffer, 0, bytesRead);
 840
 841                if (resultHandler != null) {
 842                  totalBytes += bytesRead;
 843                  status.SetBytesTested(totalBytes);
 844                  resultHandler(status, null);
 845                }
 846              }
 847            }
 848
 849            if (this[entryIndex].Crc != crc.Value) {
 850              status.AddError();
 851
 852              if (resultHandler != null) {
 853                resultHandler(status, "CRC mismatch");
 854              }
 855
 856              testing &= strategy != TestStrategy.FindFirstError;
 857            }
 858
 859            if ((this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 860              var helper = new ZipHelperStream(baseStream_);
 861              var data = new DescriptorData();
 862              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
 863              if (this[entryIndex].Crc != data.Crc) {
 864                status.AddError();
 865              }
 866
 867              if (this[entryIndex].CompressedSize != data.CompressedSize) {
 868                status.AddError();
 869              }
 870
 871              if (this[entryIndex].Size != data.Size) {
 872                status.AddError();
 873              }
 874            }
 875          }
 876
 877          if (resultHandler != null) {
 878            status.SetOperation(TestOperation.EntryComplete);
 879            resultHandler(status, null);
 880          }
 881
 882          entryIndex += 1;
 883        }
 884
 885        if (resultHandler != null) {
 886          status.SetOperation(TestOperation.MiscellaneousTests);
 887          resultHandler(status, null);
 888        }
 889
 890        // TODO: the 'Corrina Johns' test where local headers are missing from
 891        // the central directory.  They are therefore invisible to many archivers.
 892      } catch (Exception ex) {
 893        status.AddError();
 894
 895        if (resultHandler != null) {
 896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
 897        }
 898      }
 899
 900      if (resultHandler != null) {
 901        status.SetOperation(TestOperation.Complete);
 902        status.SetEntry(null);
 903        resultHandler(status, null);
 904      }
 905
 906      return (status.ErrorCount == 0);
 907    }
 908
 909    [Flags]
 910    enum HeaderTest
 911    {
 912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted
 913      Header = 0x02,     // Check that this header contents are valid
 914    }
 915
 916    /// <summary>
 917    /// Test a local header against that provided from the central directory
 918    /// </summary>
 919    /// <param name="entry">
 920    /// The entry to test against
 921    /// </param>
 922    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
 923    /// <returns>The offset of the entries data in the file</returns>
 924    long TestLocalHeader(ZipEntry entry, HeaderTest tests)
 925    {
 926      lock (baseStream_) {
 927        bool testHeader = (tests & HeaderTest.Header) != 0;
 928        bool testData = (tests & HeaderTest.Extract) != 0;
 929
 930        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
 931        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
 932          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)
 933        }
 934
 935        var extractVersion = (short)(ReadLEUshort() & 0x00ff);
 936        var localFlags = (short)ReadLEUshort();
 937        var compressionMethod = (short)ReadLEUshort();
 938        var fileTime = (short)ReadLEUshort();
 939        var fileDate = (short)ReadLEUshort();
 940        uint crcValue = ReadLEUint();
 941        long compressedSize = ReadLEUint();
 942        long size = ReadLEUint();
 943        int storedNameLength = ReadLEUshort();
 944        int extraDataLength = ReadLEUshort();
 945
 946        byte[] nameData = new byte[storedNameLength];
 947        StreamUtils.ReadFully(baseStream_, nameData);
 948
 949        byte[] extraData = new byte[extraDataLength];
 950        StreamUtils.ReadFully(baseStream_, extraData);
 951
 952        var localExtraData = new ZipExtraData(extraData);
 953
 954        // Extra data / zip64 checks
 955        if (localExtraData.Find(1)) {
 956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
 957          // and size or compressedSize = MaxValue, due to rogue creators.
 958
 959          size = localExtraData.ReadLong();
 960          compressedSize = localExtraData.ReadLong();
 961
 962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {
 963            // These may be valid if patched later
 964            if ((size != -1) && (size != entry.Size)) {
 965              throw new ZipException("Size invalid for descriptor");
 966            }
 967
 968            if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {
 969              throw new ZipException("Compressed size invalid for descriptor");
 970            }
 971          }
 972        } else {
 973          // No zip64 extra data but entry requires it.
 974          if ((extractVersion >= ZipConstants.VersionZip64) &&
 975            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) {
 976            throw new ZipException("Required Zip64 extended information missing");
 977          }
 978        }
 979
 980        if (testData) {
 981          if (entry.IsFile) {
 982            if (!entry.IsCompressionMethodSupported()) {
 983              throw new ZipException("Compression method not supported");
 984            }
 985
 986            if ((extractVersion > ZipConstants.VersionMadeBy)
 987              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64))) {
 988              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract
 989            }
 990
 991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance
 992              throw new ZipException("The library does not support the zip version required to extract this entry");
 993            }
 994          }
 995        }
 996
 997        if (testHeader) {
 998          if ((extractVersion <= 63) &&   // Ignore later versions as we dont know about them..
 999            (extractVersion != 10) &&
 1000            (extractVersion != 11) &&
 1001            (extractVersion != 20) &&
 1002            (extractVersion != 21) &&
 1003            (extractVersion != 25) &&
 1004            (extractVersion != 27) &&
 1005            (extractVersion != 45) &&
 1006            (extractVersion != 46) &&
 1007            (extractVersion != 50) &&
 1008            (extractVersion != 51) &&
 1009            (extractVersion != 52) &&
 1010            (extractVersion != 61) &&
 1011            (extractVersion != 62) &&
 1012            (extractVersion != 63)
 1013            ) {
 1014            throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersi
 1015          }
 1016
 1017          // Local entry flags dont have reserved bit set on.
 1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R
 1019            throw new ZipException("Reserved bit flags cannot be set.");
 1020          }
 1021
 1022          // Encryption requires extract version >= 20
 1023          if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) {
 1024            throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})
 1025          }
 1026
 1027          // Strong encryption requires encryption flag to be set and extract version >= 50.
 1028          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1029            if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) {
 1030              throw new ZipException("Strong encryption flag set but encryption flag is not set");
 1031            }
 1032
 1033            if (extractVersion < 50) {
 1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0
 1035            }
 1036          }
 1037
 1038          // Patched entries require extract version >= 27
 1039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {
 1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
 1041          }
 1042
 1043          // Central header flags match local entry flags.
 1044          if (localFlags != entry.Flags) {
 1045            throw new ZipException("Central header/local header flags mismatch");
 1046          }
 1047
 1048          // Central header compression method matches local entry
 1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {
 1050            throw new ZipException("Central header/local header compression method mismatch");
 1051          }
 1052
 1053          if (entry.Version != extractVersion) {
 1054            throw new ZipException("Extract version mismatch");
 1055          }
 1056
 1057          // Strong encryption and extract version match
 1058          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1059            if (extractVersion < 62) {
 1060              throw new ZipException("Strong encryption flag set but version not high enough");
 1061            }
 1062          }
 1063
 1064          if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) {
 1065            if ((fileTime != 0) || (fileDate != 0)) {
 1066              throw new ZipException("Header masked set but date/time values non-zero");
 1067            }
 1068          }
 1069
 1070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
 1071            if (crcValue != (uint)entry.Crc) {
 1072              throw new ZipException("Central header/local header crc mismatch");
 1073            }
 1074          }
 1075
 1076          // Crc valid for empty entry.
 1077          // This will also apply to streamed entries where size isnt known and the header cant be patched
 1078          if ((size == 0) && (compressedSize == 0)) {
 1079            if (crcValue != 0) {
 1080              throw new ZipException("Invalid CRC for empty entry");
 1081            }
 1082          }
 1083
 1084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str
 1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
 1086          if (entry.Name.Length > storedNameLength) {
 1087            throw new ZipException("File name length mismatch");
 1088          }
 1089
 1090          // Name data has already been read convert it and compare.
 1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);
 1092
 1093          // Central directory and local entry name match
 1094          if (localName != entry.Name) {
 1095            throw new ZipException("Central header and local header file name mismatch");
 1096          }
 1097
 1098          // Directories have zero actual size but can have compressed size
 1099          if (entry.IsDirectory) {
 1100            if (size > 0) {
 1101              throw new ZipException("Directory cannot have size");
 1102            }
 1103
 1104            // There may be other cases where the compressed size can be greater than this?
 1105            // If so until details are known we will be strict.
 1106            if (entry.IsCrypted) {
 1107              if (compressedSize > ZipConstants.CryptoHeaderSize + 2) {
 1108                throw new ZipException("Directory compressed size invalid");
 1109              }
 1110            } else if (compressedSize > 2) {
 1111              // When not compressed the directory size can validly be 2 bytes
 1112              // if the true size wasnt known when data was originally being written.
 1113              // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
 1114              throw new ZipException("Directory compressed size invalid");
 1115            }
 1116          }
 1117
 1118          if (!ZipNameTransform.IsValidName(localName, true)) {
 1119            throw new ZipException("Name is invalid");
 1120          }
 1121        }
 1122
 1123        // Tests that apply to both data and header.
 1124
 1125        // Size can be verified only if it is known in the local header.
 1126        // it will always be known in the central header.
 1127        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
 1128          ((size > 0 || compressedSize > 0) && entry.Size > 0)) {
 1129
 1130          if ((size != 0)
 1131            && (size != entry.Size)) {
 1132            throw new ZipException(
 1133              string.Format("Size mismatch between central header({0}) and local header({1})",
 1134                entry.Size, size));
 1135          }
 1136
 1137          if ((compressedSize != 0)
 1138            && (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) {
 1139            throw new ZipException(
 1140              string.Format("Compressed size mismatch between central header({0}) and local header({1})",
 1141              entry.CompressedSize, compressedSize));
 1142          }
 1143        }
 1144
 1145        int extraLength = storedNameLength + extraDataLength;
 1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
 1147      }
 1148    }
 1149
 1150    #endregion
 1151
 1152    #region Updating
 1153
 1154    const int DefaultBufferSize = 4096;
 1155
 1156    /// <summary>
 1157    /// The kind of update to apply.
 1158    /// </summary>
 1159    enum UpdateCommand
 1160    {
 1161      Copy,       // Copy original file contents.
 1162      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.
 1163      Add,        // Add a new file to the archive.
 1164    }
 1165
 1166    #region Properties
 1167    /// <summary>
 1168    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.
 1169    /// </summary>
 1170    public INameTransform NameTransform {
 1171      get {
 1172        return updateEntryFactory_.NameTransform;
 1173      }
 1174
 1175      set {
 1176        updateEntryFactory_.NameTransform = value;
 1177      }
 1178    }
 1179
 1180    /// <summary>
 1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values
 1182    /// during updates.
 1183    /// </summary>
 1184    public IEntryFactory EntryFactory {
 1185      get {
 1186        return updateEntryFactory_;
 1187      }
 1188
 1189      set {
 1190        if (value == null) {
 1191          updateEntryFactory_ = new ZipEntryFactory();
 1192        } else {
 1193          updateEntryFactory_ = value;
 1194        }
 1195      }
 1196    }
 1197
 1198    /// <summary>
 1199    /// Get /set the buffer size to be used when updating this zip file.
 1200    /// </summary>
 1201    public int BufferSize {
 1202      get { return bufferSize_; }
 1203      set {
 1204        if (value < 1024) {
 1205          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");
 1206        }
 1207
 1208        if (bufferSize_ != value) {
 1209          bufferSize_ = value;
 1210          copyBuffer_ = null;
 1211        }
 1212      }
 1213    }
 1214
 1215    /// <summary>
 1216    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.
 1217    /// </summary>
 1218    public bool IsUpdating {
 1219      get { return updates_ != null; }
 1220    }
 1221
 1222    /// <summary>
 1223    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
 1224    /// </summary>
 1225    public UseZip64 UseZip64 {
 1226      get { return useZip64_; }
 1227      set { useZip64_ = value; }
 1228    }
 1229
 1230    #endregion
 1231
 1232    #region Immediate updating
 1233    //    TBD: Direct form of updating
 1234    //
 1235    //    public void Update(IEntryMatcher deleteMatcher)
 1236    //    {
 1237    //    }
 1238    //
 1239    //    public void Update(IScanner addScanner)
 1240    //    {
 1241    //    }
 1242    #endregion
 1243
 1244    #region Deferred Updating
 1245    /// <summary>
 1246    /// Begin updating this <see cref="ZipFile"/> archive.
 1247    /// </summary>
 1248    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p
 1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param
 1250    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1251    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>
 1252    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1253    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)
 1254    {
 1255      if (archiveStorage == null) {
 1256        throw new ArgumentNullException(nameof(archiveStorage));
 1257      }
 1258
 1259      if (dataSource == null) {
 1260        throw new ArgumentNullException(nameof(dataSource));
 1261      }
 1262
 1263      if (isDisposed_) {
 1264        throw new ObjectDisposedException("ZipFile");
 1265      }
 1266
 1267      if (IsEmbeddedArchive) {
 1268        throw new ZipException("Cannot update embedded/SFX archives");
 1269      }
 1270
 1271      archiveStorage_ = archiveStorage;
 1272      updateDataSource_ = dataSource;
 1273
 1274      // NOTE: the baseStream_ may not currently support writing or seeking.
 1275
 1276      updateIndex_ = new Hashtable();
 1277
 1278      updates_ = new ArrayList(entries_.Length);
 1279      foreach (ZipEntry entry in entries_) {
 1280        int index = updates_.Add(new ZipUpdate(entry));
 1281        updateIndex_.Add(entry.Name, index);
 1282      }
 1283
 1284      // We must sort by offset before using offset's calculated sizes
 1285      updates_.Sort(new UpdateComparer());
 1286
 1287      int idx = 0;
 1288      foreach (ZipUpdate update in updates_) {
 1289        //If last entry, there is no next entry offset to use
 1290        if (idx == updates_.Count - 1)
 1291          break;
 1292
 1293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;
 1294        idx++;
 1295      }
 1296      updateCount_ = updates_.Count;
 1297
 1298      contentsEdited_ = false;
 1299      commentEdited_ = false;
 1300      newComment_ = null;
 1301    }
 1302
 1303    /// <summary>
 1304    /// Begin updating to this <see cref="ZipFile"/> archive.
 1305    /// </summary>
 1306    /// <param name="archiveStorage">The storage to use during the update.</param>
 1307    public void BeginUpdate(IArchiveStorage archiveStorage)
 1308    {
 1309      BeginUpdate(archiveStorage, new DynamicDiskDataSource());
 1310    }
 1311
 1312    /// <summary>
 1313    /// Begin updating this <see cref="ZipFile"/> archive.
 1314    /// </summary>
 1315    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>
 1316    /// <seealso cref="CommitUpdate"></seealso>
 1317    /// <seealso cref="AbortUpdate"></seealso>
 1318    public void BeginUpdate()
 1319    {
 1320      if (Name == null) {
 1321        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());
 1322      } else {
 1323        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());
 1324      }
 1325    }
 1326
 1327    /// <summary>
 1328    /// Commit current updates, updating this archive.
 1329    /// </summary>
 1330    /// <seealso cref="BeginUpdate()"></seealso>
 1331    /// <seealso cref="AbortUpdate"></seealso>
 1332    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1333    public void CommitUpdate()
 1334    {
 1335      if (isDisposed_) {
 1336        throw new ObjectDisposedException("ZipFile");
 1337      }
 1338
 1339      CheckUpdating();
 1340
 1341      try {
 1342        updateIndex_.Clear();
 1343        updateIndex_ = null;
 1344
 1345        if (contentsEdited_) {
 1346          RunUpdates();
 1347        } else if (commentEdited_) {
 1348          UpdateCommentOnly();
 1349        } else {
 1350          // Create an empty archive if none existed originally.
 1351          if (entries_.Length == 0) {
 1352            byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 1353            using (ZipHelperStream zhs = new ZipHelperStream(baseStream_)) {
 1354              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
 1355            }
 1356          }
 1357        }
 1358
 1359      } finally {
 1360        PostUpdateCleanup();
 1361      }
 1362    }
 1363
 1364    /// <summary>
 1365    /// Abort updating leaving the archive unchanged.
 1366    /// </summary>
 1367    /// <seealso cref="BeginUpdate()"></seealso>
 1368    /// <seealso cref="CommitUpdate"></seealso>
 1369    public void AbortUpdate()
 1370    {
 1371      PostUpdateCleanup();
 1372    }
 1373
 1374    /// <summary>
 1375    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.
 1376    /// </summary>
 1377    /// <param name="comment">The comment to record.</param>
 1378    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1379    public void SetComment(string comment)
 1380    {
 1381      if (isDisposed_) {
 1382        throw new ObjectDisposedException("ZipFile");
 1383      }
 1384
 1385      CheckUpdating();
 1386
 1387      newComment_ = new ZipString(comment);
 1388
 1389      if (newComment_.RawLength > 0xffff) {
 1390        newComment_ = null;
 1391        throw new ZipException("Comment length exceeds maximum - 65535");
 1392      }
 1393
 1394      // We dont take account of the original and current comment appearing to be the same
 1395      // as encoding may be different.
 1396      commentEdited_ = true;
 1397    }
 1398
 1399    #endregion
 1400
 1401    #region Adding Entries
 1402
 1403    void AddUpdate(ZipUpdate update)
 1404    {
 1405      contentsEdited_ = true;
 1406
 1407      int index = FindExistingUpdate(update.Entry.Name);
 1408
 1409      if (index >= 0) {
 1410        if (updates_[index] == null) {
 1411          updateCount_ += 1;
 1412        }
 1413
 1414        // Direct replacement is faster than delete and add.
 1415        updates_[index] = update;
 1416      } else {
 1417        index = updates_.Add(update);
 1418        updateCount_ += 1;
 1419        updateIndex_.Add(update.Entry.Name, index);
 1420      }
 1421    }
 1422
 1423    /// <summary>
 1424    /// Add a new entry to the archive.
 1425    /// </summary>
 1426    /// <param name="fileName">The name of the file to add.</param>
 1427    /// <param name="compressionMethod">The compression method to use.</param>
 1428    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>
 1429    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1430    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1431    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>
 1432    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText)
 1433    {
 1434      if (fileName == null) {
 1435        throw new ArgumentNullException(nameof(fileName));
 1436      }
 1437
 1438      if (isDisposed_) {
 1439        throw new ObjectDisposedException("ZipFile");
 1440      }
 1441
 1442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1444      }
 1445
 1446      CheckUpdating();
 1447      contentsEdited_ = true;
 1448
 1449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1450      entry.IsUnicodeText = useUnicodeText;
 1451      entry.CompressionMethod = compressionMethod;
 1452
 1453      AddUpdate(new ZipUpdate(fileName, entry));
 1454    }
 1455
 1456    /// <summary>
 1457    /// Add a new entry to the archive.
 1458    /// </summary>
 1459    /// <param name="fileName">The name of the file to add.</param>
 1460    /// <param name="compressionMethod">The compression method to use.</param>
 1461    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>
 1462    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>
 1463    public void Add(string fileName, CompressionMethod compressionMethod)
 1464    {
 1465      if (fileName == null) {
 1466        throw new ArgumentNullException(nameof(fileName));
 1467      }
 1468
 1469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1471      }
 1472
 1473      CheckUpdating();
 1474      contentsEdited_ = true;
 1475
 1476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1477      entry.CompressionMethod = compressionMethod;
 1478      AddUpdate(new ZipUpdate(fileName, entry));
 1479    }
 1480
 1481    /// <summary>
 1482    /// Add a file to the archive.
 1483    /// </summary>
 1484    /// <param name="fileName">The name of the file to add.</param>
 1485    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1486    public void Add(string fileName)
 1487    {
 1488      if (fileName == null) {
 1489        throw new ArgumentNullException(nameof(fileName));
 1490      }
 1491
 1492      CheckUpdating();
 1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));
 1494    }
 1495
 1496    /// <summary>
 1497    /// Add a file to the archive.
 1498    /// </summary>
 1499    /// <param name="fileName">The name of the file to add.</param>
 1500    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>
 1501    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1502    public void Add(string fileName, string entryName)
 1503    {
 1504      if (fileName == null) {
 1505        throw new ArgumentNullException(nameof(fileName));
 1506      }
 1507
 1508      if (entryName == null) {
 1509        throw new ArgumentNullException(nameof(entryName));
 1510      }
 1511
 1512      CheckUpdating();
 1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));
 1514    }
 1515
 1516
 1517    /// <summary>
 1518    /// Add a file entry with data.
 1519    /// </summary>
 1520    /// <param name="dataSource">The source of the data for this entry.</param>
 1521    /// <param name="entryName">The name to give to the entry.</param>
 1522    public void Add(IStaticDataSource dataSource, string entryName)
 1523    {
 1524      if (dataSource == null) {
 1525        throw new ArgumentNullException(nameof(dataSource));
 1526      }
 1527
 1528      if (entryName == null) {
 1529        throw new ArgumentNullException(nameof(entryName));
 1530      }
 1531
 1532      CheckUpdating();
 1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));
 1534    }
 1535
 1536    /// <summary>
 1537    /// Add a file entry with data.
 1538    /// </summary>
 1539    /// <param name="dataSource">The source of the data for this entry.</param>
 1540    /// <param name="entryName">The name to give to the entry.</param>
 1541    /// <param name="compressionMethod">The compression method to use.</param>
 1542    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 1543    {
 1544      if (dataSource == null) {
 1545        throw new ArgumentNullException(nameof(dataSource));
 1546      }
 1547
 1548      if (entryName == null) {
 1549        throw new ArgumentNullException(nameof(entryName));
 1550      }
 1551
 1552      CheckUpdating();
 1553
 1554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1555      entry.CompressionMethod = compressionMethod;
 1556
 1557      AddUpdate(new ZipUpdate(dataSource, entry));
 1558    }
 1559
 1560    /// <summary>
 1561    /// Add a file entry with data.
 1562    /// </summary>
 1563    /// <param name="dataSource">The source of the data for this entry.</param>
 1564    /// <param name="entryName">The name to give to the entry.</param>
 1565    /// <param name="compressionMethod">The compression method to use.</param>
 1566    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>
 1567    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode
 1568    {
 1569      if (dataSource == null) {
 1570        throw new ArgumentNullException(nameof(dataSource));
 1571      }
 1572
 1573      if (entryName == null) {
 1574        throw new ArgumentNullException(nameof(entryName));
 1575      }
 1576
 1577      CheckUpdating();
 1578
 1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1580      entry.IsUnicodeText = useUnicodeText;
 1581      entry.CompressionMethod = compressionMethod;
 1582
 1583      AddUpdate(new ZipUpdate(dataSource, entry));
 1584    }
 1585
 1586    /// <summary>
 1587    /// Add a <see cref="ZipEntry"/> that contains no data.
 1588    /// </summary>
 1589    /// <param name="entry">The entry to add.</param>
 1590    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
 1591    public void Add(ZipEntry entry)
 1592    {
 1593      if (entry == null) {
 1594        throw new ArgumentNullException(nameof(entry));
 1595      }
 1596
 1597      CheckUpdating();
 1598
 1599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {
 1600        throw new ZipException("Entry cannot have any data");
 1601      }
 1602
 1603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
 1604    }
 1605
 1606    /// <summary>
 1607    /// Add a directory entry to the archive.
 1608    /// </summary>
 1609    /// <param name="directoryName">The directory to add.</param>
 1610    public void AddDirectory(string directoryName)
 1611    {
 1612      if (directoryName == null) {
 1613        throw new ArgumentNullException(nameof(directoryName));
 1614      }
 1615
 1616      CheckUpdating();
 1617
 1618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);
 1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));
 1620    }
 1621
 1622    #endregion
 1623
 1624    #region Modifying Entries
 1625    /* Modify not yet ready for public consumption.
 1626       Direct modification of an entry should not overwrite original data before its read.
 1627       Safe mode is trivial in this sense.
 1628        public void Modify(ZipEntry original, ZipEntry updated)
 1629        {
 1630          if ( original == null ) {
 1631            throw new ArgumentNullException("original");
 1632          }
 1633
 1634          if ( updated == null ) {
 1635            throw new ArgumentNullException("updated");
 1636          }
 1637
 1638          CheckUpdating();
 1639          contentsEdited_ = true;
 1640          updates_.Add(new ZipUpdate(original, updated));
 1641        }
 1642    */
 1643    #endregion
 1644
 1645    #region Deleting Entries
 1646    /// <summary>
 1647    /// Delete an entry by name
 1648    /// </summary>
 1649    /// <param name="fileName">The filename to delete</param>
 1650    /// <returns>True if the entry was found and deleted; false otherwise.</returns>
 1651    public bool Delete(string fileName)
 1652    {
 1653      if (fileName == null) {
 1654        throw new ArgumentNullException(nameof(fileName));
 1655      }
 1656
 1657      CheckUpdating();
 1658
 1659      bool result = false;
 1660      int index = FindExistingUpdate(fileName);
 1661      if ((index >= 0) && (updates_[index] != null)) {
 1662        result = true;
 1663        contentsEdited_ = true;
 1664        updates_[index] = null;
 1665        updateCount_ -= 1;
 1666      } else {
 1667        throw new ZipException("Cannot find entry to delete");
 1668      }
 1669      return result;
 1670    }
 1671
 1672    /// <summary>
 1673    /// Delete a <see cref="ZipEntry"/> from the archive.
 1674    /// </summary>
 1675    /// <param name="entry">The entry to delete.</param>
 1676    public void Delete(ZipEntry entry)
 1677    {
 1678      if (entry == null) {
 1679        throw new ArgumentNullException(nameof(entry));
 1680      }
 1681
 1682      CheckUpdating();
 1683
 1684      int index = FindExistingUpdate(entry);
 1685      if (index >= 0) {
 1686        contentsEdited_ = true;
 1687        updates_[index] = null;
 1688        updateCount_ -= 1;
 1689      } else {
 1690        throw new ZipException("Cannot find entry to delete");
 1691      }
 1692    }
 1693
 1694    #endregion
 1695
 1696    #region Update Support
 1697
 1698    #region Writing Values/Headers
 1699    void WriteLEShort(int value)
 1700    {
 1701      baseStream_.WriteByte((byte)(value & 0xff));
 1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));
 1703    }
 1704
 1705    /// <summary>
 1706    /// Write an unsigned short in little endian byte order.
 1707    /// </summary>
 1708    void WriteLEUshort(ushort value)
 1709    {
 1710      baseStream_.WriteByte((byte)(value & 0xff));
 1711      baseStream_.WriteByte((byte)(value >> 8));
 1712    }
 1713
 1714    /// <summary>
 1715    /// Write an int in little endian byte order.
 1716    /// </summary>
 1717    void WriteLEInt(int value)
 1718    {
 1719      WriteLEShort(value & 0xffff);
 1720      WriteLEShort(value >> 16);
 1721    }
 1722
 1723    /// <summary>
 1724    /// Write an unsigned int in little endian byte order.
 1725    /// </summary>
 1726    void WriteLEUint(uint value)
 1727    {
 1728      WriteLEUshort((ushort)(value & 0xffff));
 1729      WriteLEUshort((ushort)(value >> 16));
 1730    }
 1731
 1732    /// <summary>
 1733    /// Write a long in little endian byte order.
 1734    /// </summary>
 1735    void WriteLeLong(long value)
 1736    {
 1737      WriteLEInt((int)(value & 0xffffffff));
 1738      WriteLEInt((int)(value >> 32));
 1739    }
 1740
 1741    void WriteLEUlong(ulong value)
 1742    {
 1743      WriteLEUint((uint)(value & 0xffffffff));
 1744      WriteLEUint((uint)(value >> 32));
 1745    }
 1746
 1747    void WriteLocalEntryHeader(ZipUpdate update)
 1748    {
 1749      ZipEntry entry = update.OutEntry;
 1750
 1751      // TODO: Local offset will require adjusting for multi-disk zip files.
 1752      entry.Offset = baseStream_.Position;
 1753
 1754      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
 1755      if (update.Command != UpdateCommand.Copy) {
 1756        if (entry.CompressionMethod == CompressionMethod.Deflated) {
 1757          if (entry.Size == 0) {
 1758            // No need to compress - no data.
 1759            entry.CompressedSize = entry.Size;
 1760            entry.Crc = 0;
 1761            entry.CompressionMethod = CompressionMethod.Stored;
 1762          }
 1763        } else if (entry.CompressionMethod == CompressionMethod.Stored) {
 1764          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
 1765        }
 1766
 1767        if (HaveKeys) {
 1768          entry.IsCrypted = true;
 1769          if (entry.Crc < 0) {
 1770            entry.Flags |= (int)GeneralBitFlags.Descriptor;
 1771          }
 1772        } else {
 1773          entry.IsCrypted = false;
 1774        }
 1775
 1776        switch (useZip64_) {
 1777          case UseZip64.Dynamic:
 1778            if (entry.Size < 0) {
 1779              entry.ForceZip64();
 1780            }
 1781            break;
 1782
 1783          case UseZip64.On:
 1784            entry.ForceZip64();
 1785            break;
 1786
 1787          case UseZip64.Off:
 1788            // Do nothing.  The entry itself may be using Zip64 independantly.
 1789            break;
 1790        }
 1791      }
 1792
 1793      // Write the local file header
 1794      WriteLEInt(ZipConstants.LocalHeaderSignature);
 1795
 1796      WriteLEShort(entry.Version);
 1797      WriteLEShort(entry.Flags);
 1798
 1799      WriteLEShort((byte)entry.CompressionMethod);
 1800      WriteLEInt((int)entry.DosTime);
 1801
 1802      if (!entry.HasCrc) {
 1803        // Note patch address for updating CRC later.
 1804        update.CrcPatchOffset = baseStream_.Position;
 1805        WriteLEInt((int)0);
 1806      } else {
 1807        WriteLEInt(unchecked((int)entry.Crc));
 1808      }
 1809
 1810      if (entry.LocalHeaderRequiresZip64) {
 1811        WriteLEInt(-1);
 1812        WriteLEInt(-1);
 1813      } else {
 1814        if ((entry.CompressedSize < 0) || (entry.Size < 0)) {
 1815          update.SizePatchOffset = baseStream_.Position;
 1816        }
 1817
 1818        WriteLEInt((int)entry.CompressedSize);
 1819        WriteLEInt((int)entry.Size);
 1820      }
 1821
 1822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1823
 1824      if (name.Length > 0xFFFF) {
 1825        throw new ZipException("Entry name too long.");
 1826      }
 1827
 1828      var ed = new ZipExtraData(entry.ExtraData);
 1829
 1830      if (entry.LocalHeaderRequiresZip64) {
 1831        ed.StartNewEntry();
 1832
 1833        // Local entry header always includes size and compressed size.
 1834        // NOTE the order of these fields is reversed when compared to the normal headers!
 1835        ed.AddLeLong(entry.Size);
 1836        ed.AddLeLong(entry.CompressedSize);
 1837        ed.AddNewEntry(1);
 1838      } else {
 1839        ed.Delete(1);
 1840      }
 1841
 1842      entry.ExtraData = ed.GetEntryData();
 1843
 1844      WriteLEShort(name.Length);
 1845      WriteLEShort(entry.ExtraData.Length);
 1846
 1847      if (name.Length > 0) {
 1848        baseStream_.Write(name, 0, name.Length);
 1849      }
 1850
 1851      if (entry.LocalHeaderRequiresZip64) {
 1852        if (!ed.Find(1)) {
 1853          throw new ZipException("Internal error cannot find extra data");
 1854        }
 1855
 1856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
 1857      }
 1858
 1859      if (entry.ExtraData.Length > 0) {
 1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
 1861      }
 1862    }
 1863
 1864    int WriteCentralDirectoryHeader(ZipEntry entry)
 1865    {
 1866      if (entry.CompressedSize < 0) {
 1867        throw new ZipException("Attempt to write central directory entry with unknown csize");
 1868      }
 1869
 1870      if (entry.Size < 0) {
 1871        throw new ZipException("Attempt to write central directory entry with unknown size");
 1872      }
 1873
 1874      if (entry.Crc < 0) {
 1875        throw new ZipException("Attempt to write central directory entry with unknown crc");
 1876      }
 1877
 1878      // Write the central file header
 1879      WriteLEInt(ZipConstants.CentralHeaderSignature);
 1880
 1881      // Version made by
 1882      WriteLEShort(ZipConstants.VersionMadeBy);
 1883
 1884      // Version required to extract
 1885      WriteLEShort(entry.Version);
 1886
 1887      WriteLEShort(entry.Flags);
 1888
 1889      unchecked {
 1890        WriteLEShort((byte)entry.CompressionMethod);
 1891        WriteLEInt((int)entry.DosTime);
 1892        WriteLEInt((int)entry.Crc);
 1893      }
 1894
 1895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {
 1896        WriteLEInt(-1);
 1897      } else {
 1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
 1899      }
 1900
 1901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {
 1902        WriteLEInt(-1);
 1903      } else {
 1904        WriteLEInt((int)entry.Size);
 1905      }
 1906
 1907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1908
 1909      if (name.Length > 0xFFFF) {
 1910        throw new ZipException("Entry name is too long.");
 1911      }
 1912
 1913      WriteLEShort(name.Length);
 1914
 1915      // Central header extra data is different to local header version so regenerate.
 1916      var ed = new ZipExtraData(entry.ExtraData);
 1917
 1918      if (entry.CentralHeaderRequiresZip64) {
 1919        ed.StartNewEntry();
 1920
 1921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1922          ed.AddLeLong(entry.Size);
 1923        }
 1924
 1925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1926          ed.AddLeLong(entry.CompressedSize);
 1927        }
 1928
 1929        if (entry.Offset >= 0xffffffff) {
 1930          ed.AddLeLong(entry.Offset);
 1931        }
 1932
 1933        // Number of disk on which this file starts isnt supported and is never written here.
 1934        ed.AddNewEntry(1);
 1935      } else {
 1936        // Should have already be done when local header was added.
 1937        ed.Delete(1);
 1938      }
 1939
 1940      byte[] centralExtraData = ed.GetEntryData();
 1941
 1942      WriteLEShort(centralExtraData.Length);
 1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);
 1944
 1945      WriteLEShort(0);    // disk number
 1946      WriteLEShort(0);    // internal file attributes
 1947
 1948      // External file attributes...
 1949      if (entry.ExternalFileAttributes != -1) {
 1950        WriteLEInt(entry.ExternalFileAttributes);
 1951      } else {
 1952        if (entry.IsDirectory) {
 1953          WriteLEUint(16);
 1954        } else {
 1955          WriteLEUint(0);
 1956        }
 1957      }
 1958
 1959      if (entry.Offset >= 0xffffffff) {
 1960        WriteLEUint(0xffffffff);
 1961      } else {
 1962        WriteLEUint((uint)(int)entry.Offset);
 1963      }
 1964
 1965      if (name.Length > 0) {
 1966        baseStream_.Write(name, 0, name.Length);
 1967      }
 1968
 1969      if (centralExtraData.Length > 0) {
 1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
 1971      }
 1972
 1973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];
 1974
 1975      if (rawComment.Length > 0) {
 1976        baseStream_.Write(rawComment, 0, rawComment.Length);
 1977      }
 1978
 1979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
 1980    }
 1981    #endregion
 1982
 1983    void PostUpdateCleanup()
 1984    {
 1985      updateDataSource_ = null;
 1986      updates_ = null;
 1987      updateIndex_ = null;
 1988
 1989      if (archiveStorage_ != null) {
 1990        archiveStorage_.Dispose();
 1991        archiveStorage_ = null;
 1992      }
 1993    }
 1994
 1995    string GetTransformedFileName(string name)
 1996    {
 1997      INameTransform transform = NameTransform;
 1998      return (transform != null) ?
 1999        transform.TransformFile(name) :
 2000        name;
 2001    }
 2002
 2003    string GetTransformedDirectoryName(string name)
 2004    {
 2005      INameTransform transform = NameTransform;
 2006      return (transform != null) ?
 2007        transform.TransformDirectory(name) :
 2008        name;
 2009    }
 2010
 2011    /// <summary>
 2012    /// Get a raw memory buffer.
 2013    /// </summary>
 2014    /// <returns>Returns a raw memory buffer.</returns>
 2015    byte[] GetBuffer()
 2016    {
 2017      if (copyBuffer_ == null) {
 2018        copyBuffer_ = new byte[bufferSize_];
 2019      }
 2020      return copyBuffer_;
 2021    }
 2022
 2023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)
 2024    {
 2025      int bytesToCopy = GetDescriptorSize(update);
 2026
 2027      if (bytesToCopy > 0) {
 2028        byte[] buffer = GetBuffer();
 2029
 2030        while (bytesToCopy > 0) {
 2031          int readSize = Math.Min(buffer.Length, bytesToCopy);
 2032
 2033          int bytesRead = source.Read(buffer, 0, readSize);
 2034          if (bytesRead > 0) {
 2035            dest.Write(buffer, 0, bytesRead);
 2036            bytesToCopy -= bytesRead;
 2037          } else {
 2038            throw new ZipException("Unxpected end of stream");
 2039          }
 2040        }
 2041      }
 2042    }
 2043
 2044    void CopyBytes(ZipUpdate update, Stream destination, Stream source,
 2045      long bytesToCopy, bool updateCrc)
 2046    {
 2047      if (destination == source) {
 2048        throw new InvalidOperationException("Destination and source are the same");
 2049      }
 2050
 2051      // NOTE: Compressed size is updated elsewhere.
 2052      var crc = new Crc32();
 2053      byte[] buffer = GetBuffer();
 2054
 2055      long targetBytes = bytesToCopy;
 2056      long totalBytesRead = 0;
 2057
 2058      int bytesRead;
 2059      do {
 2060        int readSize = buffer.Length;
 2061
 2062        if (bytesToCopy < readSize) {
 2063          readSize = (int)bytesToCopy;
 2064        }
 2065
 2066        bytesRead = source.Read(buffer, 0, readSize);
 2067        if (bytesRead > 0) {
 2068          if (updateCrc) {
 2069            crc.Update(buffer, 0, bytesRead);
 2070          }
 2071          destination.Write(buffer, 0, bytesRead);
 2072          bytesToCopy -= bytesRead;
 2073          totalBytesRead += bytesRead;
 2074        }
 2075      }
 2076      while ((bytesRead > 0) && (bytesToCopy > 0));
 2077
 2078      if (totalBytesRead != targetBytes) {
 2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2080      }
 2081
 2082      if (updateCrc) {
 2083        update.OutEntry.Crc = crc.Value;
 2084      }
 2085    }
 2086
 2087    /// <summary>
 2088    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
 2089    /// </summary>
 2090    /// <param name="update">The update to get the size for.</param>
 2091    /// <returns>The descriptor size, zero if there isnt one.</returns>
 2092    int GetDescriptorSize(ZipUpdate update)
 2093    {
 2094      int result = 0;
 2095      if ((update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 2096        result = ZipConstants.DataDescriptorSize - 4;
 2097        if (update.Entry.LocalHeaderRequiresZip64) {
 2098          result = ZipConstants.Zip64DataDescriptorSize - 4;
 2099        }
 2100      }
 2101      return result;
 2102    }
 2103
 2104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
 2105    {
 2106      int bytesToCopy = GetDescriptorSize(update);
 2107
 2108      while (bytesToCopy > 0) {
 2109        var readSize = (int)bytesToCopy;
 2110        byte[] buffer = GetBuffer();
 2111
 2112        stream.Position = sourcePosition;
 2113        int bytesRead = stream.Read(buffer, 0, readSize);
 2114        if (bytesRead > 0) {
 2115          stream.Position = destinationPosition;
 2116          stream.Write(buffer, 0, bytesRead);
 2117          bytesToCopy -= bytesRead;
 2118          destinationPosition += bytesRead;
 2119          sourcePosition += bytesRead;
 2120        } else {
 2121          throw new ZipException("Unxpected end of stream");
 2122        }
 2123      }
 2124    }
 2125
 2126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou
 2127    {
 2128      long bytesToCopy = update.Entry.CompressedSize;
 2129
 2130      // NOTE: Compressed size is updated elsewhere.
 2131      var crc = new Crc32();
 2132      byte[] buffer = GetBuffer();
 2133
 2134      long targetBytes = bytesToCopy;
 2135      long totalBytesRead = 0;
 2136
 2137      int bytesRead;
 2138      do {
 2139        int readSize = buffer.Length;
 2140
 2141        if (bytesToCopy < readSize) {
 2142          readSize = (int)bytesToCopy;
 2143        }
 2144
 2145        stream.Position = sourcePosition;
 2146        bytesRead = stream.Read(buffer, 0, readSize);
 2147        if (bytesRead > 0) {
 2148          if (updateCrc) {
 2149            crc.Update(buffer, 0, bytesRead);
 2150          }
 2151          stream.Position = destinationPosition;
 2152          stream.Write(buffer, 0, bytesRead);
 2153
 2154          destinationPosition += bytesRead;
 2155          sourcePosition += bytesRead;
 2156          bytesToCopy -= bytesRead;
 2157          totalBytesRead += bytesRead;
 2158        }
 2159      }
 2160      while ((bytesRead > 0) && (bytesToCopy > 0));
 2161
 2162      if (totalBytesRead != targetBytes) {
 2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2164      }
 2165
 2166      if (updateCrc) {
 2167        update.OutEntry.Crc = crc.Value;
 2168      }
 2169    }
 2170
 2171    int FindExistingUpdate(ZipEntry entry)
 2172    {
 2173      int result = -1;
 2174      string convertedName = GetTransformedFileName(entry.Name);
 2175
 2176      if (updateIndex_.ContainsKey(convertedName)) {
 2177        result = (int)updateIndex_[convertedName];
 2178      }
 2179      /*
 2180            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2181            // for CF?
 2182            for (int index = 0; index < updates_.Count; ++index)
 2183            {
 2184              ZipUpdate zu = ( ZipUpdate )updates_[index];
 2185              if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
 2186                (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
 2187                result = index;
 2188                break;
 2189              }
 2190            }
 2191       */
 2192      return result;
 2193    }
 2194
 2195    int FindExistingUpdate(string fileName)
 2196    {
 2197      int result = -1;
 2198
 2199      string convertedName = GetTransformedFileName(fileName);
 2200
 2201      if (updateIndex_.ContainsKey(convertedName)) {
 2202        result = (int)updateIndex_[convertedName];
 2203      }
 2204
 2205      /*
 2206            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2207            // for CF?
 2208            for ( int index = 0; index < updates_.Count; ++index ) {
 2209              if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,
 2210                true, CultureInfo.InvariantCulture) == 0 ) {
 2211                result = index;
 2212                break;
 2213              }
 2214            }
 2215       */
 2216
 2217      return result;
 2218    }
 2219
 2220    /// <summary>
 2221    /// Get an output stream for the specified <see cref="ZipEntry"/>
 2222    /// </summary>
 2223    /// <param name="entry">The entry to get an output stream for.</param>
 2224    /// <returns>The output stream obtained for the entry.</returns>
 2225    Stream GetOutputStream(ZipEntry entry)
 2226    {
 2227      Stream result = baseStream_;
 2228
 2229      if (entry.IsCrypted == true) {
 2230        result = CreateAndInitEncryptionStream(result, entry);
 2231      }
 2232
 2233      switch (entry.CompressionMethod) {
 2234        case CompressionMethod.Stored:
 2235          result = new UncompressedStream(result);
 2236          break;
 2237
 2238        case CompressionMethod.Deflated:
 2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));
 2240          dos.IsStreamOwner = false;
 2241          result = dos;
 2242          break;
 2243
 2244        default:
 2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);
 2246      }
 2247      return result;
 2248    }
 2249
 2250    void AddEntry(ZipFile workFile, ZipUpdate update)
 2251    {
 2252      Stream source = null;
 2253
 2254      if (update.Entry.IsFile) {
 2255        source = update.GetSource();
 2256
 2257        if (source == null) {
 2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);
 2259        }
 2260      }
 2261
 2262      if (source != null) {
 2263        using (source) {
 2264          long sourceStreamLength = source.Length;
 2265          if (update.OutEntry.Size < 0) {
 2266            update.OutEntry.Size = sourceStreamLength;
 2267          } else {
 2268            // Check for errant entries.
 2269            if (update.OutEntry.Size != sourceStreamLength) {
 2270              throw new ZipException("Entry size/stream size mismatch");
 2271            }
 2272          }
 2273
 2274          workFile.WriteLocalEntryHeader(update);
 2275
 2276          long dataStart = workFile.baseStream_.Position;
 2277
 2278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2279            CopyBytes(update, output, source, sourceStreamLength, true);
 2280          }
 2281
 2282          long dataEnd = workFile.baseStream_.Position;
 2283          update.OutEntry.CompressedSize = dataEnd - dataStart;
 2284
 2285          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor) {
 2286            var helper = new ZipHelperStream(workFile.baseStream_);
 2287            helper.WriteDataDescriptor(update.OutEntry);
 2288          }
 2289        }
 2290      } else {
 2291        workFile.WriteLocalEntryHeader(update);
 2292        update.OutEntry.CompressedSize = 0;
 2293      }
 2294
 2295    }
 2296
 2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)
 2298    {
 2299      workFile.WriteLocalEntryHeader(update);
 2300      long dataStart = workFile.baseStream_.Position;
 2301
 2302      // TODO: This is slow if the changes don't effect the data!!
 2303      if (update.Entry.IsFile && (update.Filename != null)) {
 2304        using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2305          using (Stream source = this.GetInputStream(update.Entry)) {
 2306            CopyBytes(update, output, source, source.Length, true);
 2307          }
 2308        }
 2309      }
 2310
 2311      long dataEnd = workFile.baseStream_.Position;
 2312      update.Entry.CompressedSize = dataEnd - dataStart;
 2313    }
 2314
 2315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)
 2316    {
 2317      bool skipOver = false || update.Entry.Offset == destinationPosition;
 2318
 2319      if (!skipOver) {
 2320        baseStream_.Position = destinationPosition;
 2321        workFile.WriteLocalEntryHeader(update);
 2322        destinationPosition = baseStream_.Position;
 2323      }
 2324
 2325      long sourcePosition = 0;
 2326
 2327      const int NameLengthOffset = 26;
 2328
 2329      // TODO: Add base for SFX friendly handling
 2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2331
 2332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2333
 2334      // Clumsy way of handling retrieving the original name and extra data length for now.
 2335      // TODO: Stop re-reading name and data length in CopyEntryDirect.
 2336      uint nameLength = ReadLEUshort();
 2337      uint extraLength = ReadLEUshort();
 2338
 2339      sourcePosition = baseStream_.Position + nameLength + extraLength;
 2340
 2341      if (skipOver) {
 2342        if (update.OffsetBasedSize != -1)
 2343          destinationPosition += update.OffsetBasedSize;
 2344        else
 2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar
 2346          // WinZip produces a warning on these entries:
 2347          // "caution: value of lrec.csize (compressed size) changed from ..."
 2348          destinationPosition +=
 2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size
 2350            update.Entry.CompressedSize + GetDescriptorSize(update);
 2351      } else {
 2352        if (update.Entry.CompressedSize > 0) {
 2353          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition);
 2354        }
 2355        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
 2356      }
 2357    }
 2358
 2359    void CopyEntry(ZipFile workFile, ZipUpdate update)
 2360    {
 2361      workFile.WriteLocalEntryHeader(update);
 2362
 2363      if (update.Entry.CompressedSize > 0) {
 2364        const int NameLengthOffset = 26;
 2365
 2366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2367
 2368        // TODO: This wont work for SFX files!
 2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2370
 2371        uint nameLength = ReadLEUshort();
 2372        uint extraLength = ReadLEUshort();
 2373
 2374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);
 2375
 2376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
 2377      }
 2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
 2379    }
 2380
 2381    void Reopen(Stream source)
 2382    {
 2383      if (source == null) {
 2384        throw new ZipException("Failed to reopen archive - no source");
 2385      }
 2386
 2387      isNewArchive_ = false;
 2388      baseStream_ = source;
 2389      ReadEntries();
 2390    }
 2391
 2392    void Reopen()
 2393    {
 2394      if (Name == null) {
 2395        throw new InvalidOperationException("Name is not known cannot Reopen");
 2396      }
 2397
 2398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));
 2399    }
 2400
 2401    void UpdateCommentOnly()
 2402    {
 2403      long baseLength = baseStream_.Length;
 2404
 2405      ZipHelperStream updateFile = null;
 2406
 2407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
 2409        updateFile = new ZipHelperStream(copyStream);
 2410        updateFile.IsStreamOwner = true;
 2411
 2412        baseStream_.Close();
 2413        baseStream_ = null;
 2414      } else {
 2415        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2416          // TODO: archiveStorage wasnt originally intended for this use.
 2417          // Need to revisit this to tidy up handling as archive storage currently doesnt
 2418          // handle the original stream well.
 2419          // The problem is when using an existing zip archive with an in memory archive storage.
 2420          // The open stream wont support writing but the memory storage should open the same file not an in memory one.
 2421
 2422          // Need to tidy up the archive storage interface and contract basically.
 2423          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);
 2424          updateFile = new ZipHelperStream(baseStream_);
 2425        } else {
 2426          baseStream_.Close();
 2427          baseStream_ = null;
 2428          updateFile = new ZipHelperStream(Name);
 2429        }
 2430      }
 2431
 2432      using (updateFile) {
 2433        long locatedCentralDirOffset =
 2434          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2435                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2436        if (locatedCentralDirOffset < 0) {
 2437          throw new ZipException("Cannot find central directory");
 2438        }
 2439
 2440        const int CentralHeaderCommentSizeOffset = 16;
 2441        updateFile.Position += CentralHeaderCommentSizeOffset;
 2442
 2443        byte[] rawComment = newComment_.RawComment;
 2444
 2445        updateFile.WriteLEShort(rawComment.Length);
 2446        updateFile.Write(rawComment, 0, rawComment.Length);
 2447        updateFile.SetLength(updateFile.Position);
 2448      }
 2449
 2450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2452      } else {
 2453        ReadEntries();
 2454      }
 2455    }
 2456
 2457    /// <summary>
 2458    /// Class used to sort updates.
 2459    /// </summary>
 2460    class UpdateComparer : IComparer
 2461    {
 2462      /// <summary>
 2463      /// Compares two objects and returns a value indicating whether one is
 2464      /// less than, equal to or greater than the other.
 2465      /// </summary>
 2466      /// <param name="x">First object to compare</param>
 2467      /// <param name="y">Second object to compare.</param>
 2468      /// <returns>Compare result.</returns>
 2469      public int Compare(
 2470        object x,
 2471        object y)
 2472      {
 2473        var zx = x as ZipUpdate;
 2474        var zy = y as ZipUpdate;
 2475
 2476        int result;
 2477
 2478        if (zx == null) {
 2479          if (zy == null) {
 2480            result = 0;
 2481          } else {
 2482            result = -1;
 2483          }
 2484        } else if (zy == null) {
 2485          result = 1;
 2486        } else {
 2487          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;
 2488          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;
 2489
 2490          result = xCmdValue - yCmdValue;
 2491          if (result == 0) {
 2492            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;
 2493            if (offsetDiff < 0) {
 2494              result = -1;
 2495            } else if (offsetDiff == 0) {
 2496              result = 0;
 2497            } else {
 2498              result = 1;
 2499            }
 2500          }
 2501        }
 2502        return result;
 2503      }
 2504    }
 2505
 2506    void RunUpdates()
 2507    {
 2508      long sizeEntries = 0;
 2509      long endOfStream = 0;
 2510      bool directUpdate = false;
 2511      long destinationPosition = 0; // NOT SFX friendly
 2512
 2513      ZipFile workFile;
 2514
 2515      if (IsNewArchive) {
 2516        workFile = this;
 2517        workFile.baseStream_.Position = 0;
 2518        directUpdate = true;
 2519      } else if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2520        workFile = this;
 2521        workFile.baseStream_.Position = 0;
 2522        directUpdate = true;
 2523
 2524        // Sort the updates by offset within copies/modifies, then adds.
 2525        // This ensures that data required by copies will not be overwritten.
 2526        updates_.Sort(new UpdateComparer());
 2527      } else {
 2528        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
 2529        workFile.UseZip64 = UseZip64;
 2530
 2531        if (key != null) {
 2532          workFile.key = (byte[])key.Clone();
 2533        }
 2534      }
 2535
 2536      try {
 2537        foreach (ZipUpdate update in updates_) {
 2538          if (update != null) {
 2539            switch (update.Command) {
 2540              case UpdateCommand.Copy:
 2541                if (directUpdate) {
 2542                  CopyEntryDirect(workFile, update, ref destinationPosition);
 2543                } else {
 2544                  CopyEntry(workFile, update);
 2545                }
 2546                break;
 2547
 2548              case UpdateCommand.Modify:
 2549                // TODO: Direct modifying of an entry will take some legwork.
 2550                ModifyEntry(workFile, update);
 2551                break;
 2552
 2553              case UpdateCommand.Add:
 2554                if (!IsNewArchive && directUpdate) {
 2555                  workFile.baseStream_.Position = destinationPosition;
 2556                }
 2557
 2558                AddEntry(workFile, update);
 2559
 2560                if (directUpdate) {
 2561                  destinationPosition = workFile.baseStream_.Position;
 2562                }
 2563                break;
 2564            }
 2565          }
 2566        }
 2567
 2568        if (!IsNewArchive && directUpdate) {
 2569          workFile.baseStream_.Position = destinationPosition;
 2570        }
 2571
 2572        long centralDirOffset = workFile.baseStream_.Position;
 2573
 2574        foreach (ZipUpdate update in updates_) {
 2575          if (update != null) {
 2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
 2577          }
 2578        }
 2579
 2580        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 2581        using (ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_)) {
 2582          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);
 2583        }
 2584
 2585        endOfStream = workFile.baseStream_.Position;
 2586
 2587        // And now patch entries...
 2588        foreach (ZipUpdate update in updates_) {
 2589          if (update != null) {
 2590            // If the size of the entry is zero leave the crc as 0 as well.
 2591            // The calculated crc will be all bits on...
 2592            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {
 2593              workFile.baseStream_.Position = update.CrcPatchOffset;
 2594              workFile.WriteLEInt((int)update.OutEntry.Crc);
 2595            }
 2596
 2597            if (update.SizePatchOffset > 0) {
 2598              workFile.baseStream_.Position = update.SizePatchOffset;
 2599              if (update.OutEntry.LocalHeaderRequiresZip64) {
 2600                workFile.WriteLeLong(update.OutEntry.Size);
 2601                workFile.WriteLeLong(update.OutEntry.CompressedSize);
 2602              } else {
 2603                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);
 2604                workFile.WriteLEInt((int)update.OutEntry.Size);
 2605              }
 2606            }
 2607          }
 2608        }
 2609      } catch {
 2610        workFile.Close();
 2611        if (!directUpdate && (workFile.Name != null)) {
 2612          File.Delete(workFile.Name);
 2613        }
 2614        throw;
 2615      }
 2616
 2617      if (directUpdate) {
 2618        workFile.baseStream_.SetLength(endOfStream);
 2619        workFile.baseStream_.Flush();
 2620        isNewArchive_ = false;
 2621        ReadEntries();
 2622      } else {
 2623        baseStream_.Close();
 2624        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2625      }
 2626    }
 2627
 2628    void CheckUpdating()
 2629    {
 2630      if (updates_ == null) {
 2631        throw new InvalidOperationException("BeginUpdate has not been called");
 2632      }
 2633    }
 2634
 2635    #endregion
 2636
 2637    #region ZipUpdate class
 2638    /// <summary>
 2639    /// Represents a pending update to a Zip file.
 2640    /// </summary>
 2641    class ZipUpdate
 2642    {
 2643      #region Constructors
 2644      public ZipUpdate(string fileName, ZipEntry entry)
 2645      {
 2646        command_ = UpdateCommand.Add;
 2647        entry_ = entry;
 2648        filename_ = fileName;
 2649      }
 2650
 2651      [Obsolete]
 2652      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 2653      {
 2654        command_ = UpdateCommand.Add;
 2655        entry_ = new ZipEntry(entryName);
 2656        entry_.CompressionMethod = compressionMethod;
 2657        filename_ = fileName;
 2658      }
 2659
 2660      [Obsolete]
 2661      public ZipUpdate(string fileName, string entryName)
 2662        : this(fileName, entryName, CompressionMethod.Deflated)
 2663      {
 2664        // Do nothing.
 2665      }
 2666
 2667      [Obsolete]
 2668      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 2669      {
 2670        command_ = UpdateCommand.Add;
 2671        entry_ = new ZipEntry(entryName);
 2672        entry_.CompressionMethod = compressionMethod;
 2673        dataSource_ = dataSource;
 2674      }
 2675
 2676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 2677      {
 2678        command_ = UpdateCommand.Add;
 2679        entry_ = entry;
 2680        dataSource_ = dataSource;
 2681      }
 2682
 2683      public ZipUpdate(ZipEntry original, ZipEntry updated)
 2684      {
 2685        throw new ZipException("Modify not currently supported");
 2686        /*
 2687          command_ = UpdateCommand.Modify;
 2688          entry_ = ( ZipEntry )original.Clone();
 2689          outEntry_ = ( ZipEntry )updated.Clone();
 2690        */
 2691      }
 2692
 2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)
 2694      {
 2695        command_ = command;
 2696        entry_ = (ZipEntry)entry.Clone();
 2697      }
 2698
 2699
 2700      /// <summary>
 2701      /// Copy an existing entry.
 2702      /// </summary>
 2703      /// <param name="entry">The existing entry to copy.</param>
 2704      public ZipUpdate(ZipEntry entry)
 2705        : this(UpdateCommand.Copy, entry)
 2706      {
 2707        // Do nothing.
 2708      }
 2709      #endregion
 2710
 2711      /// <summary>
 2712      /// Get the <see cref="ZipEntry"/> for this update.
 2713      /// </summary>
 2714      /// <remarks>This is the source or original entry.</remarks>
 2715      public ZipEntry Entry {
 2716        get { return entry_; }
 2717      }
 2718
 2719      /// <summary>
 2720      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.
 2721      /// </summary>
 2722      public ZipEntry OutEntry {
 2723        get {
 2724          if (outEntry_ == null) {
 2725            outEntry_ = (ZipEntry)entry_.Clone();
 2726          }
 2727
 2728          return outEntry_;
 2729        }
 2730      }
 2731
 2732      /// <summary>
 2733      /// Get the command for this update.
 2734      /// </summary>
 2735      public UpdateCommand Command {
 2736        get { return command_; }
 2737      }
 2738
 2739      /// <summary>
 2740      /// Get the filename if any for this update.  Null if none exists.
 2741      /// </summary>
 2742      public string Filename {
 2743        get { return filename_; }
 2744      }
 2745
 2746      /// <summary>
 2747      /// Get/set the location of the size patch for this update.
 2748      /// </summary>
 2749      public long SizePatchOffset {
 2750        get { return sizePatchOffset_; }
 2751        set { sizePatchOffset_ = value; }
 2752      }
 2753
 2754      /// <summary>
 2755      /// Get /set the location of the crc patch for this update.
 2756      /// </summary>
 2757      public long CrcPatchOffset {
 2758        get { return crcPatchOffset_; }
 2759        set { crcPatchOffset_ = value; }
 2760      }
 2761
 2762      /// <summary>
 2763      /// Get/set the size calculated by offset.
 2764      /// Specifically, the difference between this and next entry's starting offset.
 2765      /// </summary>
 2766      public long OffsetBasedSize {
 2767        get { return _offsetBasedSize; }
 2768        set { _offsetBasedSize = value; }
 2769      }
 2770
 2771      public Stream GetSource()
 2772      {
 2773        Stream result = null;
 2774        if (dataSource_ != null) {
 2775          result = dataSource_.GetSource();
 2776        }
 2777
 2778        return result;
 2779      }
 2780
 2781      #region Instance Fields
 2782      ZipEntry entry_;
 2783      ZipEntry outEntry_;
 2784      UpdateCommand command_;
 2785      IStaticDataSource dataSource_;
 2786      string filename_;
 2787      long sizePatchOffset_ = -1;
 2788      long crcPatchOffset_ = -1;
 2789      long _offsetBasedSize = -1;
 2790      #endregion
 2791    }
 2792
 2793    #endregion
 2794    #endregion
 2795
 2796    #region Disposing
 2797
 2798    #region IDisposable Members
 2799    void IDisposable.Dispose()
 2800    {
 2801      Close();
 2802    }
 2803    #endregion
 2804
 2805    void DisposeInternal(bool disposing)
 2806    {
 2807      if (!isDisposed_) {
 2808        isDisposed_ = true;
 2809        entries_ = new ZipEntry[0];
 2810
 2811        if (IsStreamOwner && (baseStream_ != null)) {
 2812          lock (baseStream_) {
 2813            baseStream_.Close();
 2814          }
 2815        }
 2816
 2817        PostUpdateCleanup();
 2818      }
 2819    }
 2820
 2821    /// <summary>
 2822    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.
 2823    /// </summary>
 2824    /// <param name="disposing">true to release both managed and unmanaged resources;
 2825    /// false to release only unmanaged resources.</param>
 2826    protected virtual void Dispose(bool disposing)
 2827    {
 2828      DisposeInternal(disposing);
 2829    }
 2830
 2831    #endregion
 2832
 2833    #region Internal routines
 2834    #region Reading
 2835    /// <summary>
 2836    /// Read an unsigned short in little endian byte order.
 2837    /// </summary>
 2838    /// <returns>Returns the value read.</returns>
 2839    /// <exception cref="EndOfStreamException">
 2840    /// The stream ends prematurely
 2841    /// </exception>
 2842    ushort ReadLEUshort()
 2843    {
 2844      int data1 = baseStream_.ReadByte();
 2845
 2846      if (data1 < 0) {
 2847        throw new EndOfStreamException("End of stream");
 2848      }
 2849
 2850      int data2 = baseStream_.ReadByte();
 2851
 2852      if (data2 < 0) {
 2853        throw new EndOfStreamException("End of stream");
 2854      }
 2855
 2856
 2857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));
 2858    }
 2859
 2860    /// <summary>
 2861    /// Read a uint in little endian byte order.
 2862    /// </summary>
 2863    /// <returns>Returns the value read.</returns>
 2864    /// <exception cref="IOException">
 2865    /// An i/o error occurs.
 2866    /// </exception>
 2867    /// <exception cref="System.IO.EndOfStreamException">
 2868    /// The file ends prematurely
 2869    /// </exception>
 2870    uint ReadLEUint()
 2871    {
 2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));
 2873    }
 2874
 2875    ulong ReadLEUlong()
 2876    {
 2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);
 2878    }
 2879
 2880    #endregion
 2881    // NOTE this returns the offset of the first byte after the signature.
 2882    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 2883    {
 2884      using (ZipHelperStream les = new ZipHelperStream(baseStream_)) {
 2885        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
 2886      }
 2887    }
 2888
 2889    /// <summary>
 2890    /// Search for and read the central directory of a zip file filling the entries array.
 2891    /// </summary>
 2892    /// <exception cref="System.IO.IOException">
 2893    /// An i/o error occurs.
 2894    /// </exception>
 2895    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 2896    /// The central directory is malformed or cannot be found
 2897    /// </exception>
 2898    void ReadEntries()
 2899    {
 2900      // Search for the End Of Central Directory.  When a zip comment is
 2901      // present the directory will start earlier
 2902      //
 2903      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
 2904      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
 2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
 2906      // this could be invalid.
 2907      // Could also speed this up by reading memory in larger blocks.
 2908
 2909      if (baseStream_.CanSeek == false) {
 2910        throw new ZipException("ZipFile stream must be seekable");
 2911      }
 2912
 2913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2915
 2916      if (locatedEndOfCentralDir < 0) {
 2917        throw new ZipException("Cannot find central directory");
 2918      }
 2919
 2920      // Read end of central directory record
 2921      ushort thisDiskNumber = ReadLEUshort();
 2922      ushort startCentralDirDisk = ReadLEUshort();
 2923      ulong entriesForThisDisk = ReadLEUshort();
 2924      ulong entriesForWholeCentralDir = ReadLEUshort();
 2925      ulong centralDirSize = ReadLEUint();
 2926      long offsetOfCentralDir = ReadLEUint();
 2927      uint commentSize = ReadLEUshort();
 2928
 2929      if (commentSize > 0) {
 2930        byte[] comment = new byte[commentSize];
 2931
 2932        StreamUtils.ReadFully(baseStream_, comment);
 2933        comment_ = ZipConstants.ConvertToString(comment);
 2934      } else {
 2935        comment_ = string.Empty;
 2936      }
 2937
 2938      bool isZip64 = false;
 2939
 2940      // Check if zip64 header information is required.
 2941      if ((thisDiskNumber == 0xffff) ||
 2942        (startCentralDirDisk == 0xffff) ||
 2943        (entriesForThisDisk == 0xffff) ||
 2944        (entriesForWholeCentralDir == 0xffff) ||
 2945        (centralDirSize == 0xffffffff) ||
 2946        (offsetOfCentralDir == 0xffffffff)) {
 2947        isZip64 = true;
 2948
 2949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 
 2950        if (offset < 0) {
 2951          throw new ZipException("Cannot find Zip64 locator");
 2952        }
 2953
 2954        // number of the disk with the start of the zip64 end of central directory 4 bytes
 2955        // relative offset of the zip64 end of central directory record 8 bytes
 2956        // total number of disks 4 bytes
 2957        ReadLEUint(); // startDisk64 is not currently used
 2958        ulong offset64 = ReadLEUlong();
 2959        uint totalDisks = ReadLEUint();
 2960
 2961        baseStream_.Position = (long)offset64;
 2962        long sig64 = ReadLEUint();
 2963
 2964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {
 2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
 2966        }
 2967
 2968        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
 2969        ulong recordSize = ReadLEUlong();
 2970        int versionMadeBy = ReadLEUshort();
 2971        int versionToExtract = ReadLEUshort();
 2972        uint thisDisk = ReadLEUint();
 2973        uint centralDirDisk = ReadLEUint();
 2974        entriesForThisDisk = ReadLEUlong();
 2975        entriesForWholeCentralDir = ReadLEUlong();
 2976        centralDirSize = ReadLEUlong();
 2977        offsetOfCentralDir = (long)ReadLEUlong();
 2978
 2979        // NOTE: zip64 extensible data sector (variable size) is ignored.
 2980      }
 2981
 2982      entries_ = new ZipEntry[entriesForThisDisk];
 2983
 2984      // SFX/embedded support, find the offset of the first entry vis the start of the stream
 2985      // This applies to Zip files that are appended to the end of an SFX stub.
 2986      // Or are appended as a resource to an executable.
 2987      // Zip files created by some archivers have the offsets altered to reflect the true offsets
 2988      // and so dont require any adjustment here...
 2989      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
 2990      if (!isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize))) {
 2991        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
 2992        if (offsetOfFirstEntry <= 0) {
 2993          throw new ZipException("Invalid embedded zip archive");
 2994        }
 2995      }
 2996
 2997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
 2998
 2999      for (ulong i = 0; i < entriesForThisDisk; i++) {
 3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
 3001          throw new ZipException("Wrong Central Directory signature");
 3002        }
 3003
 3004        int versionMadeBy = ReadLEUshort();
 3005        int versionToExtract = ReadLEUshort();
 3006        int bitFlags = ReadLEUshort();
 3007        int method = ReadLEUshort();
 3008        uint dostime = ReadLEUint();
 3009        uint crc = ReadLEUint();
 3010        var csize = (long)ReadLEUint();
 3011        var size = (long)ReadLEUint();
 3012        int nameLen = ReadLEUshort();
 3013        int extraLen = ReadLEUshort();
 3014        int commentLen = ReadLEUshort();
 3015
 3016        int diskStartNo = ReadLEUshort();  // Not currently used
 3017        int internalAttributes = ReadLEUshort();  // Not currently used
 3018
 3019        uint externalAttributes = ReadLEUint();
 3020        long offset = ReadLEUint();
 3021
 3022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
 3023
 3024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
 3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);
 3026
 3027        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
 3028        entry.Crc = crc & 0xffffffffL;
 3029        entry.Size = size & 0xffffffffL;
 3030        entry.CompressedSize = csize & 0xffffffffL;
 3031        entry.Flags = bitFlags;
 3032        entry.DosTime = (uint)dostime;
 3033        entry.ZipFileIndex = (long)i;
 3034        entry.Offset = offset;
 3035        entry.ExternalFileAttributes = (int)externalAttributes;
 3036
 3037        if ((bitFlags & 8) == 0) {
 3038          entry.CryptoCheckValue = (byte)(crc >> 24);
 3039        } else {
 3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
 3041        }
 3042
 3043        if (extraLen > 0) {
 3044          byte[] extra = new byte[extraLen];
 3045          StreamUtils.ReadFully(baseStream_, extra);
 3046          entry.ExtraData = extra;
 3047        }
 3048
 3049        entry.ProcessExtraData(false);
 3050
 3051        if (commentLen > 0) {
 3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
 3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
 3054        }
 3055
 3056        entries_[i] = entry;
 3057      }
 3058    }
 3059
 3060    /// <summary>
 3061    /// Locate the data for a given entry.
 3062    /// </summary>
 3063    /// <returns>
 3064    /// The start offset of the data.
 3065    /// </returns>
 3066    /// <exception cref="System.IO.EndOfStreamException">
 3067    /// The stream ends prematurely
 3068    /// </exception>
 3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 3070    /// The local header signature is invalid, the entry and central header file name lengths are different
 3071    /// or the local and entry compression methods dont match
 3072    /// </exception>
 3073    long LocateEntry(ZipEntry entry)
 3074    {
 3075      return TestLocalHeader(entry, HeaderTest.Extract);
 3076    }
 3077
 3078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
 3079    {
 3080      CryptoStream result = null;
 3081
 3082      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3084        var classicManaged = new PkzipClassicManaged();
 3085
 3086        OnKeysRequired(entry.Name);
 3087        if (HaveKeys == false) {
 3088          throw new ZipException("No password available for encrypted stream");
 3089        }
 3090
 3091        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
 3092        CheckClassicPassword(result, entry);
 3093      } else {
 3094        if (entry.Version == ZipConstants.VERSION_AES) {
 3095          //
 3096          OnKeysRequired(entry.Name);
 3097          if (HaveKeys == false) {
 3098            throw new ZipException("No password available for AES encrypted stream");
 3099          }
 3100          int saltLen = entry.AESSaltLen;
 3101          byte[] saltBytes = new byte[saltLen];
 3102          int saltIn = baseStream.Read(saltBytes, 0, saltLen);
 3103          if (saltIn != saltLen)
 3104            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
 3105          //
 3106          byte[] pwdVerifyRead = new byte[2];
 3107          baseStream.Read(pwdVerifyRead, 0, 2);
 3108          int blockSize = entry.AESKeySize / 8;   // bits to bytes
 3109
 3110          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
 3111          byte[] pwdVerifyCalc = decryptor.PwdVerifier;
 3112          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
 3113            throw new ZipException("Invalid password for AES");
 3114          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
 3115        } else {
 3116          throw new ZipException("Decryption method not supported");
 3117        }
 3118      }
 3119
 3120      return result;
 3121    }
 3122
 3123    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
 3124    {
 3125      CryptoStream result = null;
 3126      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3127        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3128        var classicManaged = new PkzipClassicManaged();
 3129
 3130        OnKeysRequired(entry.Name);
 3131        if (HaveKeys == false) {
 3132          throw new ZipException("No password available for encrypted stream");
 3133        }
 3134
 3135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
 3136        // which doesnt do this.
 3137        result = new CryptoStream(new UncompressedStream(baseStream),
 3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
 3139
 3140        if ((entry.Crc < 0) || (entry.Flags & 8) != 0) {
 3141          WriteEncryptionHeader(result, entry.DosTime << 16);
 3142        } else {
 3143          WriteEncryptionHeader(result, entry.Crc);
 3144        }
 3145      }
 3146      return result;
 3147    }
 3148
 3149    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
 3150    {
 3151      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
 3152      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
 3153      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
 3154        throw new ZipException("Invalid password");
 3155      }
 3156    }
 3157
 3158    static void WriteEncryptionHeader(Stream stream, long crcValue)
 3159    {
 3160      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
 3161      var rnd = new Random();
 3162      rnd.NextBytes(cryptBuffer);
 3163      cryptBuffer[11] = (byte)(crcValue >> 24);
 3164      stream.Write(cryptBuffer, 0, cryptBuffer.Length);
 3165    }
 3166
 3167    #endregion
 3168
 3169    #region Instance Fields
 3170    bool isDisposed_;
 3171    string name_;
 3172    string comment_;
 3173    string rawPassword_;
 3174    Stream baseStream_;
 3175    bool isStreamOwner;
 3176    long offsetOfFirstEntry;
 3177    ZipEntry[] entries_;
 3178    byte[] key;
 3179    bool isNewArchive_;
 3180
 3181    // Default is dynamic which is not backwards compatible and can cause problems
 3182    // with XP's built in compression which cant read Zip64 archives.
 3183    // However it does avoid the situation were a large file is added and cannot be completed correctly.
 3184    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.
 3185    UseZip64 useZip64_ = UseZip64.Dynamic;
 3186
 3187    #region Zip Update Instance Fields
 3188    ArrayList updates_;
 3189    long updateCount_; // Count is managed manually as updates_ can contain nulls!
 3190    Hashtable updateIndex_;
 3191    IArchiveStorage archiveStorage_;
 3192    IDynamicDataSource updateDataSource_;
 3193    bool contentsEdited_;
 3194    int bufferSize_ = DefaultBufferSize;
 3195    byte[] copyBuffer_;
 3196    ZipString newComment_;
 3197    bool commentEdited_;
 3198    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();
 3199    #endregion
 3200    #endregion
 3201
 3202    #region Support Classes
 3203    /// <summary>
 3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.
 3205    /// </summary>
 3206    class ZipString
 3207    {
 3208      #region Constructors
 3209      /// <summary>
 3210      /// Initialise a <see cref="ZipString"/> with a string.
 3211      /// </summary>
 3212      /// <param name="comment">The textual string form.</param>
 3213      public ZipString(string comment)
 3214      {
 3215        comment_ = comment;
 3216        isSourceString_ = true;
 3217      }
 3218
 3219      /// <summary>
 3220      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.
 3221      /// </summary>
 3222      /// <param name="rawString"></param>
 3223      public ZipString(byte[] rawString)
 3224      {
 3225        rawComment_ = rawString;
 3226      }
 3227      #endregion
 3228
 3229      /// <summary>
 3230      /// Get a value indicating the original source of data for this instance.
 3231      /// True if the source was a string; false if the source was binary data.
 3232      /// </summary>
 3233      public bool IsSourceString {
 3234        get { return isSourceString_; }
 3235      }
 3236
 3237      /// <summary>
 3238      /// Get the length of the comment when represented as raw bytes.
 3239      /// </summary>
 3240      public int RawLength {
 3241        get {
 3242          MakeBytesAvailable();
 3243          return rawComment_.Length;
 3244        }
 3245      }
 3246
 3247      /// <summary>
 3248      /// Get the comment in its 'raw' form as plain bytes.
 3249      /// </summary>
 3250      public byte[] RawComment {
 3251        get {
 3252          MakeBytesAvailable();
 3253          return (byte[])rawComment_.Clone();
 3254        }
 3255      }
 3256
 3257      /// <summary>
 3258      /// Reset the comment to its initial state.
 3259      /// </summary>
 3260      public void Reset()
 3261      {
 3262        if (isSourceString_) {
 3263          rawComment_ = null;
 3264        } else {
 3265          comment_ = null;
 3266        }
 3267      }
 3268
 3269      void MakeTextAvailable()
 3270      {
 3271        if (comment_ == null) {
 3272          comment_ = ZipConstants.ConvertToString(rawComment_);
 3273        }
 3274      }
 3275
 3276      void MakeBytesAvailable()
 3277      {
 3278        if (rawComment_ == null) {
 3279          rawComment_ = ZipConstants.ConvertToArray(comment_);
 3280        }
 3281      }
 3282
 3283      /// <summary>
 3284      /// Implicit conversion of comment to a string.
 3285      /// </summary>
 3286      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>
 3287      /// <returns>The textual equivalent for the input value.</returns>
 3288      static public implicit operator string(ZipString zipString)
 3289      {
 3290        zipString.MakeTextAvailable();
 3291        return zipString.comment_;
 3292      }
 3293
 3294      #region Instance Fields
 3295      string comment_;
 3296      byte[] rawComment_;
 3297      bool isSourceString_;
 3298      #endregion
 3299    }
 3300
 3301    /// <summary>
 3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>
 3303    /// </summary>
 3304    class ZipEntryEnumerator : IEnumerator
 3305    {
 3306      #region Constructors
 3307      public ZipEntryEnumerator(ZipEntry[] entries)
 3308      {
 3309        array = entries;
 3310      }
 3311
 3312      #endregion
 3313      #region IEnumerator Members
 3314      public object Current {
 3315        get {
 3316          return array[index];
 3317        }
 3318      }
 3319
 3320      public void Reset()
 3321      {
 3322        index = -1;
 3323      }
 3324
 3325      public bool MoveNext()
 3326      {
 3327        return (++index < array.Length);
 3328      }
 3329      #endregion
 3330      #region Instance Fields
 3331      ZipEntry[] array;
 3332      int index = -1;
 3333      #endregion
 3334    }
 3335
 3336    /// <summary>
 3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data
 3338    /// to and flush, but cannot read, seek or do anything else to.
 3339    /// </summary>
 3340    class UncompressedStream : Stream
 3341    {
 3342      #region Constructors
 3343      public UncompressedStream(Stream baseStream)
 3344      {
 3345        baseStream_ = baseStream;
 3346      }
 3347
 3348      #endregion
 3349
 3350      /// <summary>
 3351      /// Close this stream instance.
 3352      /// </summary>
 3353      public override void Close()
 3354      {
 3355        // Do nothing
 3356      }
 3357
 3358      /// <summary>
 3359      /// Gets a value indicating whether the current stream supports reading.
 3360      /// </summary>
 3361      public override bool CanRead {
 3362        get {
 3363          return false;
 3364        }
 3365      }
 3366
 3367      /// <summary>
 3368      /// Write any buffered data to underlying storage.
 3369      /// </summary>
 3370      public override void Flush()
 3371      {
 3372        baseStream_.Flush();
 3373      }
 3374
 3375      /// <summary>
 3376      /// Gets a value indicating whether the current stream supports writing.
 3377      /// </summary>
 3378      public override bool CanWrite {
 3379        get {
 3380          return baseStream_.CanWrite;
 3381        }
 3382      }
 3383
 3384      /// <summary>
 3385      /// Gets a value indicating whether the current stream supports seeking.
 3386      /// </summary>
 3387      public override bool CanSeek {
 3388        get {
 3389          return false;
 3390        }
 3391      }
 3392
 3393      /// <summary>
 3394      /// Get the length in bytes of the stream.
 3395      /// </summary>
 3396      public override long Length {
 3397        get {
 3398          return 0;
 3399        }
 3400      }
 3401
 3402      /// <summary>
 3403      /// Gets or sets the position within the current stream.
 3404      /// </summary>
 3405      public override long Position {
 3406        get {
 3407          return baseStream_.Position;
 3408        }
 3409        set {
 3410          throw new NotImplementedException();
 3411        }
 3412      }
 3413
 3414      /// <summary>
 3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3416      /// </summary>
 3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3419      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3420      /// <returns>
 3421      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3422      /// </returns>
 3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3425      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3426      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3427      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3428      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3429      public override int Read(byte[] buffer, int offset, int count)
 3430      {
 3431        return 0;
 3432      }
 3433
 3434      /// <summary>
 3435      /// Sets the position within the current stream.
 3436      /// </summary>
 3437      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3438      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3439      /// <returns>
 3440      /// The new position within the current stream.
 3441      /// </returns>
 3442      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3443      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3445      public override long Seek(long offset, SeekOrigin origin)
 3446      {
 3447        return 0;
 3448      }
 3449
 3450      /// <summary>
 3451      /// Sets the length of the current stream.
 3452      /// </summary>
 3453      /// <param name="value">The desired length of the current stream in bytes.</param>
 3454      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3455      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3456      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3457      public override void SetLength(long value)
 3458      {
 3459      }
 3460
 3461      /// <summary>
 3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3463      /// </summary>
 3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3466      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3467      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3468      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3469      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3470      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3471      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3472      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3473      public override void Write(byte[] buffer, int offset, int count)
 3474      {
 3475        baseStream_.Write(buffer, offset, count);
 3476      }
 3477
 3478      readonly
 3479
 3480      #region Instance Fields
 3481      Stream baseStream_;
 3482      #endregion
 3483    }
 3484
 3485    /// <summary>
 3486    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>
 3487    /// whose data is only a part or subsection of a file.
 3488    /// </summary>
 3489    class PartialInputStream : Stream
 3490    {
 3491      #region Constructors
 3492      /// <summary>
 3493      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.
 3494      /// </summary>
 3495      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>
 3496      /// <param name="start">The start of the partial data.</param>
 3497      /// <param name="length">The length of the partial data.</param>
 3498      public PartialInputStream(ZipFile zipFile, long start, long length)
 3499      {
 3500        start_ = start;
 3501        length_ = length;
 3502
 3503        // Although this is the only time the zipfile is used
 3504        // keeping a reference here prevents premature closure of
 3505        // this zip file and thus the baseStream_.
 3506
 3507        // Code like this will cause apparently random failures depending
 3508        // on the size of the files and when garbage is collected.
 3509        //
 3510        // ZipFile z = new ZipFile (stream);
 3511        // Stream reader = z.GetInputStream(0);
 3512        // uses reader here....
 3513        zipFile_ = zipFile;
 3514        baseStream_ = zipFile_.baseStream_;
 3515        readPos_ = start;
 3516        end_ = start + length;
 3517      }
 3518      #endregion
 3519
 3520      /// <summary>
 3521      /// Read a byte from this stream.
 3522      /// </summary>
 3523      /// <returns>Returns the byte read or -1 on end of stream.</returns>
 3524      public override int ReadByte()
 3525      {
 3526        if (readPos_ >= end_) {
 3527          // -1 is the correct value at end of stream.
 3528          return -1;
 3529        }
 3530
 3531        lock (baseStream_) {
 3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);
 3533          return baseStream_.ReadByte();
 3534        }
 3535      }
 3536
 3537      /// <summary>
 3538      /// Close this <see cref="PartialInputStream">partial input stream</see>.
 3539      /// </summary>
 3540      /// <remarks>
 3541      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.
 3542      /// </remarks>
 3543      public override void Close()
 3544      {
 3545        // Do nothing at all!
 3546      }
 3547
 3548      /// <summary>
 3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3550      /// </summary>
 3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3553      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3554      /// <returns>
 3555      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3556      /// </returns>
 3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3559      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3560      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3561      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3562      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3563      public override int Read(byte[] buffer, int offset, int count)
 3564      {
 3565        lock (baseStream_) {
 3566          if (count > end_ - readPos_) {
 3567            count = (int)(end_ - readPos_);
 3568            if (count == 0) {
 3569              return 0;
 3570            }
 3571          }
 3572          // Protect against Stream implementations that throw away their buffer on every Seek
 3573          // (for example, Mono FileStream)
 3574          if (baseStream_.Position != readPos_) {
 3575            baseStream_.Seek(readPos_, SeekOrigin.Begin);
 3576          }
 3577          int readCount = baseStream_.Read(buffer, offset, count);
 3578          if (readCount > 0) {
 3579            readPos_ += readCount;
 3580          }
 3581          return readCount;
 3582        }
 3583      }
 3584
 3585      /// <summary>
 3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3587      /// </summary>
 3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3590      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3591      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3592      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3593      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3594      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3595      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3596      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3597      public override void Write(byte[] buffer, int offset, int count)
 3598      {
 3599        throw new NotSupportedException();
 3600      }
 3601
 3602      /// <summary>
 3603      /// When overridden in a derived class, sets the length of the current stream.
 3604      /// </summary>
 3605      /// <param name="value">The desired length of the current stream in bytes.</param>
 3606      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3607      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3608      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3609      public override void SetLength(long value)
 3610      {
 3611        throw new NotSupportedException();
 3612      }
 3613
 3614      /// <summary>
 3615      /// When overridden in a derived class, sets the position within the current stream.
 3616      /// </summary>
 3617      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3618      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3619      /// <returns>
 3620      /// The new position within the current stream.
 3621      /// </returns>
 3622      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3623      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3625      public override long Seek(long offset, SeekOrigin origin)
 3626      {
 3627        long newPos = readPos_;
 3628
 3629        switch (origin) {
 3630          case SeekOrigin.Begin:
 3631            newPos = start_ + offset;
 3632            break;
 3633
 3634          case SeekOrigin.Current:
 3635            newPos = readPos_ + offset;
 3636            break;
 3637
 3638          case SeekOrigin.End:
 3639            newPos = end_ + offset;
 3640            break;
 3641        }
 3642
 3643        if (newPos < start_) {
 3644          throw new ArgumentException("Negative position is invalid");
 3645        }
 3646
 3647        if (newPos >= end_) {
 3648          throw new IOException("Cannot seek past end");
 3649        }
 3650        readPos_ = newPos;
 3651        return readPos_;
 3652      }
 3653
 3654      /// <summary>
 3655      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
 3656      /// </summary>
 3657      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3658      public override void Flush()
 3659      {
 3660        // Nothing to do.
 3661      }
 3662
 3663      /// <summary>
 3664      /// Gets or sets the position within the current stream.
 3665      /// </summary>
 3666      /// <value></value>
 3667      /// <returns>The current position within the stream.</returns>
 3668      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3669      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>
 3670      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3671      public override long Position {
 3672        get { return readPos_ - start_; }
 3673        set {
 3674          long newPos = start_ + value;
 3675
 3676          if (newPos < start_) {
 3677            throw new ArgumentException("Negative position is invalid");
 3678          }
 3679
 3680          if (newPos >= end_) {
 3681            throw new InvalidOperationException("Cannot seek past end");
 3682          }
 3683          readPos_ = newPos;
 3684        }
 3685      }
 3686
 3687      /// <summary>
 3688      /// Gets the length in bytes of the stream.
 3689      /// </summary>
 3690      /// <value></value>
 3691      /// <returns>A long value representing the length of the stream in bytes.</returns>
 3692      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep
 3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3694      public override long Length {
 3695        get { return length_; }
 3696      }
 3697
 3698      /// <summary>
 3699      /// Gets a value indicating whether the current stream supports writing.
 3700      /// </summary>
 3701      /// <value>false</value>
 3702      /// <returns>true if the stream supports writing; otherwise, false.</returns>
 3703      public override bool CanWrite {
 3704        get { return false; }
 3705      }
 3706
 3707      /// <summary>
 3708      /// Gets a value indicating whether the current stream supports seeking.
 3709      /// </summary>
 3710      /// <value>true</value>
 3711      /// <returns>true if the stream supports seeking; otherwise, false.</returns>
 3712      public override bool CanSeek {
 3713        get { return true; }
 3714      }
 3715
 3716      /// <summary>
 3717      /// Gets a value indicating whether the current stream supports reading.
 3718      /// </summary>
 3719      /// <value>true.</value>
 3720      /// <returns>true if the stream supports reading; otherwise, false.</returns>
 3721      public override bool CanRead {
 3722        get { return true; }
 3723      }
 3724
 3725      /// <summary>
 3726      /// Gets a value that determines whether the current stream can time out.
 3727      /// </summary>
 3728      /// <value></value>
 3729      /// <returns>A value that determines whether the current stream can time out.</returns>
 3730      public override bool CanTimeout {
 3731        get { return baseStream_.CanTimeout; }
 3732      }
 3733      #region Instance Fields
 3734      ZipFile zipFile_;
 3735      Stream baseStream_;
 3736      long start_;
 3737      long length_;
 3738      long readPos_;
 3739      long end_;
 3740      #endregion
 3741    }
 3742    #endregion
 3743  }
 3744
 3745  #endregion
 3746
 3747  #region DataSources
 3748  /// <summary>
 3749  /// Provides a static way to obtain a source of data for an entry.
 3750  /// </summary>
 3751  public interface IStaticDataSource
 3752  {
 3753    /// <summary>
 3754    /// Get a source of data by creating a new stream.
 3755    /// </summary>
 3756    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3757    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3758    Stream GetSource();
 3759  }
 3760
 3761  /// <summary>
 3762  /// Represents a source of data that can dynamically provide
 3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.
 3764  /// </summary>
 3765  public interface IDynamicDataSource
 3766  {
 3767    /// <summary>
 3768    /// Get a data source.
 3769    /// </summary>
 3770    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>
 3771    /// <param name="name">The name for data if known.</param>
 3772    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3773    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3774    Stream GetSource(ZipEntry entry, string name);
 3775  }
 3776
 3777  /// <summary>
 3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.
 3779  /// </summary>
 3780  public class StaticDiskDataSource : IStaticDataSource
 3781  {
 3782    /// <summary>
 3783    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>
 3784    /// </summary>
 3785    /// <param name="fileName">The name of the file to obtain data from.</param>
 3786    public StaticDiskDataSource(string fileName)
 3787    {
 3788      fileName_ = fileName;
 3789    }
 3790
 3791    #region IDataSource Members
 3792
 3793    /// <summary>
 3794    /// Get a <see cref="Stream"/> providing data.
 3795    /// </summary>
 3796    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>
 3797    public Stream GetSource()
 3798    {
 3799      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 3800    }
 3801
 3802    readonly
 3803
 3804    #endregion
 3805    #region Instance Fields
 3806    string fileName_;
 3807    #endregion
 3808  }
 3809
 3810
 3811  /// <summary>
 3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.
 3813  /// </summary>
 3814  public class DynamicDiskDataSource : IDynamicDataSource
 3815  {
 3816
 3817    #region IDataSource Members
 3818    /// <summary>
 3819    /// Get a <see cref="Stream"/> providing data for an entry.
 3820    /// </summary>
 3821    /// <param name="entry">The entry to provide data for.</param>
 3822    /// <param name="name">The file name for data if known.</param>
 3823    /// <returns>Returns a stream providing data; or null if not available</returns>
 3824    public Stream GetSource(ZipEntry entry, string name)
 3825    {
 3826      Stream result = null;
 3827
 3828      if (name != null) {
 3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 3830      }
 3831
 3832      return result;
 3833    }
 3834
 3835    #endregion
 3836  }
 3837
 3838  #endregion
 3839
 3840  #region Archive Storage
 3841  /// <summary>
 3842  /// Defines facilities for data storage when updating Zip Archives.
 3843  /// </summary>
 3844  public interface IArchiveStorage
 3845  {
 3846    /// <summary>
 3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.
 3848    /// </summary>
 3849    FileUpdateMode UpdateMode { get; }
 3850
 3851    /// <summary>
 3852    /// Get an empty <see cref="Stream"/> that can be used for temporary output.
 3853    /// </summary>
 3854    /// <returns>Returns a temporary output <see cref="Stream"/></returns>
 3855    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3856    Stream GetTemporaryOutput();
 3857
 3858    /// <summary>
 3859    /// Convert a temporary output stream to a final stream.
 3860    /// </summary>
 3861    /// <returns>The resulting final <see cref="Stream"/></returns>
 3862    /// <seealso cref="GetTemporaryOutput"/>
 3863    Stream ConvertTemporaryToFinal();
 3864
 3865    /// <summary>
 3866    /// Make a temporary copy of the original stream.
 3867    /// </summary>
 3868    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 3869    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3870    Stream MakeTemporaryCopy(Stream stream);
 3871
 3872    /// <summary>
 3873    /// Return a stream suitable for performing direct updates on the original source.
 3874    /// </summary>
 3875    /// <param name="stream">The current stream.</param>
 3876    /// <returns>Returns a stream suitable for direct updating.</returns>
 3877    /// <remarks>This may be the current stream passed.</remarks>
 3878    Stream OpenForDirectUpdate(Stream stream);
 3879
 3880    /// <summary>
 3881    /// Dispose of this instance.
 3882    /// </summary>
 3883    void Dispose();
 3884  }
 3885
 3886  /// <summary>
 3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.
 3888  /// </summary>
 3889  abstract public class BaseArchiveStorage : IArchiveStorage
 3890  {
 3891    #region Constructors
 3892    /// <summary>
 3893    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.
 3894    /// </summary>
 3895    /// <param name="updateMode">The update mode.</param>
 483896    protected BaseArchiveStorage(FileUpdateMode updateMode)
 3897    {
 483898      updateMode_ = updateMode;
 483899    }
 3900    #endregion
 3901
 3902    #region IArchiveStorage Members
 3903
 3904    /// <summary>
 3905    /// Gets a temporary output <see cref="Stream"/>
 3906    /// </summary>
 3907    /// <returns>Returns the temporary output stream.</returns>
 3908    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3909    public abstract Stream GetTemporaryOutput();
 3910
 3911    /// <summary>
 3912    /// Converts the temporary <see cref="Stream"/> to its final form.
 3913    /// </summary>
 3914    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 3915    /// the final storage for the archive.</returns>
 3916    /// <seealso cref="GetTemporaryOutput"/>
 3917    public abstract Stream ConvertTemporaryToFinal();
 3918
 3919    /// <summary>
 3920    /// Make a temporary copy of a <see cref="Stream"/>.
 3921    /// </summary>
 3922    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>
 3923    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3924    public abstract Stream MakeTemporaryCopy(Stream stream);
 3925
 3926    /// <summary>
 3927    /// Return a stream suitable for performing direct updates on the original source.
 3928    /// </summary>
 3929    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>
 3930    /// <returns>Returns a stream suitable for direct updating.</returns>
 3931    public abstract Stream OpenForDirectUpdate(Stream stream);
 3932
 3933    /// <summary>
 3934    /// Disposes this instance.
 3935    /// </summary>
 3936    public abstract void Dispose();
 3937
 3938    /// <summary>
 3939    /// Gets the update mode applicable.
 3940    /// </summary>
 3941    /// <value>The update mode.</value>
 3942    public FileUpdateMode UpdateMode {
 3943      get {
 363944        return updateMode_;
 3945      }
 3946    }
 3947
 3948    #endregion
 3949
 3950    #region Instance Fields
 3951    FileUpdateMode updateMode_;
 3952    #endregion
 3953  }
 3954
 3955  /// <summary>
 3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.
 3957  /// </summary>
 3958  public class DiskArchiveStorage : BaseArchiveStorage
 3959  {
 3960    #region Constructors
 3961    /// <summary>
 3962    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3963    /// </summary>
 3964    /// <param name="file">The file.</param>
 3965    /// <param name="updateMode">The update mode.</param>
 3966    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)
 3967      : base(updateMode)
 3968    {
 3969      if (file.Name == null) {
 3970        throw new ZipException("Cant handle non file archives");
 3971      }
 3972
 3973      fileName_ = file.Name;
 3974    }
 3975
 3976    /// <summary>
 3977    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3978    /// </summary>
 3979    /// <param name="file">The file.</param>
 3980    public DiskArchiveStorage(ZipFile file)
 3981      : this(file, FileUpdateMode.Safe)
 3982    {
 3983    }
 3984    #endregion
 3985
 3986    #region IArchiveStorage Members
 3987
 3988    /// <summary>
 3989    /// Gets a temporary output <see cref="Stream"/> for performing updates on.
 3990    /// </summary>
 3991    /// <returns>Returns the temporary output stream.</returns>
 3992    public override Stream GetTemporaryOutput()
 3993    {
 3994      if (temporaryName_ != null) {
 3995        temporaryName_ = GetTempFileName(temporaryName_, true);
 3996        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 3997      } else {
 3998        // Determine where to place files based on internal strategy.
 3999        // Currently this is always done in system temp directory.
 4000        temporaryName_ = Path.GetTempFileName();
 4001        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 4002      }
 4003
 4004      return temporaryStream_;
 4005    }
 4006
 4007    /// <summary>
 4008    /// Converts a temporary <see cref="Stream"/> to its final form.
 4009    /// </summary>
 4010    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4011    /// the final storage for the archive.</returns>
 4012    public override Stream ConvertTemporaryToFinal()
 4013    {
 4014      if (temporaryStream_ == null) {
 4015        throw new ZipException("No temporary stream has been created");
 4016      }
 4017
 4018      Stream result = null;
 4019
 4020      string moveTempName = GetTempFileName(fileName_, false);
 4021      bool newFileCreated = false;
 4022
 4023      try {
 4024        temporaryStream_.Close();
 4025        File.Move(fileName_, moveTempName);
 4026        File.Move(temporaryName_, fileName_);
 4027        newFileCreated = true;
 4028        File.Delete(moveTempName);
 4029
 4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 4031      } catch (Exception) {
 4032        result = null;
 4033
 4034        // Try to roll back changes...
 4035        if (!newFileCreated) {
 4036          File.Move(moveTempName, fileName_);
 4037          File.Delete(temporaryName_);
 4038        }
 4039
 4040        throw;
 4041      }
 4042
 4043      return result;
 4044    }
 4045
 4046    /// <summary>
 4047    /// Make a temporary copy of a stream.
 4048    /// </summary>
 4049    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4050    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4051    public override Stream MakeTemporaryCopy(Stream stream)
 4052    {
 4053      stream.Close();
 4054
 4055      temporaryName_ = GetTempFileName(fileName_, true);
 4056      File.Copy(fileName_, temporaryName_, true);
 4057
 4058      temporaryStream_ = new FileStream(temporaryName_,
 4059        FileMode.Open,
 4060        FileAccess.ReadWrite);
 4061      return temporaryStream_;
 4062    }
 4063
 4064    /// <summary>
 4065    /// Return a stream suitable for performing direct updates on the original source.
 4066    /// </summary>
 4067    /// <param name="stream">The current stream.</param>
 4068    /// <returns>Returns a stream suitable for direct updating.</returns>
 4069    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>
 4070    public override Stream OpenForDirectUpdate(Stream stream)
 4071    {
 4072      Stream result;
 4073      if ((stream == null) || !stream.CanWrite) {
 4074        if (stream != null) {
 4075          stream.Close();
 4076        }
 4077
 4078        result = new FileStream(fileName_,
 4079            FileMode.Open,
 4080            FileAccess.ReadWrite);
 4081      } else {
 4082        result = stream;
 4083      }
 4084
 4085      return result;
 4086    }
 4087
 4088    /// <summary>
 4089    /// Disposes this instance.
 4090    /// </summary>
 4091    public override void Dispose()
 4092    {
 4093      if (temporaryStream_ != null) {
 4094        temporaryStream_.Close();
 4095      }
 4096    }
 4097
 4098    #endregion
 4099
 4100    #region Internal routines
 4101    static string GetTempFileName(string original, bool makeTempFile)
 4102    {
 4103      string result = null;
 4104
 4105      if (original == null) {
 4106        result = Path.GetTempFileName();
 4107      } else {
 4108        int counter = 0;
 4109        int suffixSeed = DateTime.Now.Second;
 4110
 4111        while (result == null) {
 4112          counter += 1;
 4113          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);
 4114          if (!File.Exists(newName)) {
 4115            if (makeTempFile) {
 4116              try {
 4117                // Try and create the file.
 4118                using (FileStream stream = File.Create(newName)) {
 4119                }
 4120                result = newName;
 4121              } catch {
 4122                suffixSeed = DateTime.Now.Second;
 4123              }
 4124            } else {
 4125              result = newName;
 4126            }
 4127          }
 4128        }
 4129      }
 4130      return result;
 4131    }
 4132    #endregion
 4133
 4134    #region Instance Fields
 4135    Stream temporaryStream_;
 4136    string fileName_;
 4137    string temporaryName_;
 4138    #endregion
 4139  }
 4140
 4141  /// <summary>
 4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.
 4143  /// </summary>
 4144  public class MemoryArchiveStorage : BaseArchiveStorage
 4145  {
 4146    #region Constructors
 4147    /// <summary>
 4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4149    /// </summary>
 4150    public MemoryArchiveStorage()
 4151      : base(FileUpdateMode.Direct)
 4152    {
 4153    }
 4154
 4155    /// <summary>
 4156    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4157    /// </summary>
 4158    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>
 4159    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>
 4160    public MemoryArchiveStorage(FileUpdateMode updateMode)
 4161      : base(updateMode)
 4162    {
 4163    }
 4164
 4165    #endregion
 4166
 4167    #region Properties
 4168    /// <summary>
 4169    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.
 4170    /// </summary>
 4171    public MemoryStream FinalStream {
 4172      get { return finalStream_; }
 4173    }
 4174
 4175    #endregion
 4176
 4177    #region IArchiveStorage Members
 4178
 4179    /// <summary>
 4180    /// Gets the temporary output <see cref="Stream"/>
 4181    /// </summary>
 4182    /// <returns>Returns the temporary output stream.</returns>
 4183    public override Stream GetTemporaryOutput()
 4184    {
 4185      temporaryStream_ = new MemoryStream();
 4186      return temporaryStream_;
 4187    }
 4188
 4189    /// <summary>
 4190    /// Converts the temporary <see cref="Stream"/> to its final form.
 4191    /// </summary>
 4192    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4193    /// the final storage for the archive.</returns>
 4194    public override Stream ConvertTemporaryToFinal()
 4195    {
 4196      if (temporaryStream_ == null) {
 4197        throw new ZipException("No temporary stream has been created");
 4198      }
 4199
 4200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());
 4201      return finalStream_;
 4202    }
 4203
 4204    /// <summary>
 4205    /// Make a temporary copy of the original stream.
 4206    /// </summary>
 4207    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4208    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4209    public override Stream MakeTemporaryCopy(Stream stream)
 4210    {
 4211      temporaryStream_ = new MemoryStream();
 4212      stream.Position = 0;
 4213      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);
 4214      return temporaryStream_;
 4215    }
 4216
 4217    /// <summary>
 4218    /// Return a stream suitable for performing direct updates on the original source.
 4219    /// </summary>
 4220    /// <param name="stream">The original source stream</param>
 4221    /// <returns>Returns a stream suitable for direct updating.</returns>
 4222    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;
 4223    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>
 4224    public override Stream OpenForDirectUpdate(Stream stream)
 4225    {
 4226      Stream result;
 4227      if ((stream == null) || !stream.CanWrite) {
 4228
 4229        result = new MemoryStream();
 4230
 4231        if (stream != null) {
 4232          stream.Position = 0;
 4233          StreamUtils.Copy(stream, result, new byte[4096]);
 4234
 4235          stream.Close();
 4236        }
 4237      } else {
 4238        result = stream;
 4239      }
 4240
 4241      return result;
 4242    }
 4243
 4244    /// <summary>
 4245    /// Disposes this instance.
 4246    /// </summary>
 4247    public override void Dispose()
 4248    {
 4249      if (temporaryStream_ != null) {
 4250        temporaryStream_.Close();
 4251      }
 4252    }
 4253
 4254    #endregion
 4255
 4256    #region Instance Fields
 4257    MemoryStream temporaryStream_;
 4258    MemoryStream finalStream_;
 4259    #endregion
 4260  }
 4261
 4262  #endregion
 4263}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_CompletedFileHandler.htm b/docs/opencover/ICSharpCode.SharpZipLib_CompletedFileHandler.htm new file mode 100644 index 000000000..2efd90445 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_CompletedFileHandler.htm @@ -0,0 +1,29 @@ + + + + +ICSharpCode.SharpZipLib.Core.CompletedFileHandler - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.CompletedFileHandler
Assembly:ICSharpCode.SharpZipLib
File(s):
Covered lines:0
Uncovered lines:0
Coverable lines:0
Total lines:0
Line coverage:
+

File(s)

+

No files found. This usually happens if a file isn't covered by a test or the class does not contain any sequence points (e.g. a class that only contains auto properties).

+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_Crc32.htm b/docs/opencover/ICSharpCode.SharpZipLib_Crc32.htm new file mode 100644 index 000000000..a34b59f50 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_Crc32.htm @@ -0,0 +1,237 @@ + + + + +ICSharpCode.SharpZipLib.Checksum.Crc32 - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Checksum.Crc32
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Checksum\Crc32.cs
Covered lines:82
Uncovered lines:0
Coverable lines:82
Total lines:189
Line coverage:100%
Branch coverage:100%
+

Metrics

+ + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
ComputeCrc32(...)1100100
.ctor()1100100
Reset()1100100
Update(...)1100100
Update(...)2100100
Update(...)7100100
.cctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Checksum\Crc32.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Checksum
 4{
 5  /// <summary>
 6  /// CRC-32 with reversed data and unreversed output
 7  /// </summary>
 8  /// <remarks>
 9  /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
 10  /// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0.
 11  ///
 12  /// Polynomials over GF(2) are represented in binary, one bit per coefficient,
 13  /// with the lowest powers in the most significant bit.  Then adding polynomials
 14  /// is just exclusive-or, and multiplying a polynomial by x is a right shift by
 15  /// one.  If we call the above polynomial p, and represent a byte as the
 16  /// polynomial q, also with the lowest power in the most significant bit (so the
 17  /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
 18  /// where a mod b means the remainder after dividing a by b.
 19  ///
 20  /// This calculation is done using the shift-register method of multiplying and
 21  /// taking the remainder.  The register is initialized to zero, and for each
 22  /// incoming bit, x^32 is added mod p to the register if the bit is a one (where
 23  /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
 24  /// x (which is shifting right by one and adding x^32 mod p if the bit shifted
 25  /// out is a one).  We start with the highest power (least significant bit) of
 26  /// q and repeat for all eight bits of q.
 27  ///
 28  /// The table is simply the CRC of all possible eight bit values.  This is all
 29  /// the information needed to generate CRC's on data a byte at a time for all
 30  /// combinations of CRC register values and incoming bytes.
 31  /// </remarks>
 32  public sealed class Crc32 : IChecksum
 33  {
 34    #region Instance Fields
 135    readonly static uint crcInit = 0xFFFFFFFF;
 136    readonly static uint crcXor = 0xFFFFFFFF;
 37
 138    readonly static uint[] crcTable = {
 139      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
 140      0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
 141      0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
 142      0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
 143      0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
 144      0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
 145      0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
 146      0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
 147      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
 148      0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
 149      0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
 150      0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
 151      0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
 152      0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
 153      0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
 154      0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
 155      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
 156      0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
 157      0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
 158      0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
 159      0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
 160      0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
 161      0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
 162      0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
 163      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
 164      0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
 165      0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
 166      0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
 167      0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
 168      0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
 169      0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
 170      0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
 171      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
 172      0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
 173      0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
 174      0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
 175      0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
 176      0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
 177      0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
 178      0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
 179      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
 180      0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
 181      0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
 182      0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
 183      0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
 184      0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
 185      0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
 186      0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
 187      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
 188      0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
 189      0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
 190      0x2D02EF8D
 191    };
 92
 93    /// <summary>
 94    /// The CRC data checksum so far.
 95    /// </summary>
 96    uint checkValue;
 97    #endregion
 98
 99    internal static uint ComputeCrc32(uint oldCrc, byte bval)
 100    {
 4516642101      return (uint)(Crc32.crcTable[(oldCrc ^ bval) & 0xFF] ^ (oldCrc >> 8));
 102    }
 103
 104    /// <summary>
 105    /// Initialise a default instance of <see cref="Crc32"></see>
 106    /// </summary>
 66290107    public Crc32()
 108    {
 66290109      Reset();
 66290110    }
 111
 112    /// <summary>
 113    /// Resets the CRC data checksum as if no update was ever called.
 114    /// </summary>
 115    public void Reset()
 116    {
 66451117      checkValue = crcInit;
 66451118    }
 119
 120    /// <summary>
 121    /// Returns the CRC data checksum computed so far.
 122    /// </summary>
 123    /// <remarks>Reversed Out = false</remarks>
 124    public long Value {
 125      get {
 66251126        return (long)(checkValue ^ crcXor);
 127      }
 128    }
 129
 130    /// <summary>
 131    /// Updates the checksum with the int bval.
 132    /// </summary>
 133    /// <param name = "bval">
 134    /// the byte is taken as the lower 8 bits of bval
 135    /// </param>
 136    /// <remarks>Reversed Data = true</remarks>
 137    public void Update(int bval)
 138    {
 4528259139      checkValue = unchecked(crcTable[(checkValue ^ bval) & 0xFF] ^ (checkValue >> 8));
 4528259140    }
 141
 142    /// <summary>
 143    /// Updates the CRC data checksum with the bytes taken from
 144    /// a block of data.
 145    /// </summary>
 146    /// <param name="buffer">Contains the data to update the CRC with.</param>
 147    public void Update(byte[] buffer)
 148    {
 2149       if (buffer == null) {
 1150        throw new ArgumentNullException(nameof(buffer));
 151      }
 152
 1153      Update(buffer, 0, buffer.Length);
 1154    }
 155
 156    /// <summary>
 157    /// Update CRC data checksum based on a portion of a block of data
 158    /// </summary>
 159    /// <param name = "buffer">Contains the data to update the CRC with.</param>
 160    /// <param name = "offset">The offset into the buffer where the data starts</param>
 161    /// <param name = "count">The number of data bytes to update the CRC with.</param>
 162    public void Update(byte[] buffer, int offset, int count)
 163    {
 5155164       if (buffer == null) {
 1165        throw new ArgumentNullException(nameof(buffer));
 166      }
 167
 5154168       if (offset < 0) {
 1169        throw new ArgumentOutOfRangeException(nameof(offset), "cannot be less than zero");
 170      }
 171
 5153172       if (offset >= buffer.Length) {
 2173        throw new ArgumentOutOfRangeException(nameof(offset), "not a valid index into buffer");
 174      }
 175
 5151176       if (count < 0) {
 1177        throw new ArgumentOutOfRangeException(nameof(count), "cannot be less than zero");
 178      }
 179
 5150180       if (offset + count > buffer.Length) {
 1181        throw new ArgumentOutOfRangeException(nameof(count), "exceeds buffer size");
 182      }
 183
 9066816184       for (int i = 0; i < count; ++i) {
 4528259185        Update(buffer[offset++]);
 186      }
 5149187    }
 188  }
 189}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_Deflater.htm b/docs/opencover/ICSharpCode.SharpZipLib_Deflater.htm new file mode 100644 index 000000000..f926a7d9a --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_Deflater.htm @@ -0,0 +1,577 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.Deflater - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.Deflater
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Deflater.cs
Covered lines:69
Uncovered lines:29
Coverable lines:98
Total lines:521
Line coverage:70.4%
Branch coverage:68%
+

Metrics

+ + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
.ctor(...)100
.ctor(...)492.3171.43
Reset()3100100
Flush()1100100
Finish()1100100
SetInput(...)100
SetInput(...)27566.67
SetLevel(...)588.8977.78
GetLevel()1100100
SetStrategy(...)1100100
Deflate(...)100
Deflate(...)1669.0570.97
SetDictionary(...)100
SetDictionary(...)200
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Deflater.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Zip.Compression
 4{
 5  /// <summary>
 6  /// This is the Deflater class.  The deflater class compresses input
 7  /// with the deflate algorithm described in RFC 1951.  It has several
 8  /// compression levels and three different strategies described below.
 9  ///
 10  /// This class is <i>not</i> thread safe.  This is inherent in the API, due
 11  /// to the split of deflate and setInput.
 12  ///
 13  /// author of the original java version : Jochen Hoenicke
 14  /// </summary>
 15  public class Deflater
 16  {
 17    #region Deflater Documentation
 18    /*
 19    * The Deflater can do the following state transitions:
 20    *
 21    * (1) -> INIT_STATE   ----> INIT_FINISHING_STATE ---.
 22    *        /  | (2)      (5)                          |
 23    *       /   v          (5)                          |
 24    *   (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)
 25    *       \   | (3)                 |        ,--------'
 26    *        |  |                     | (3)   /
 27    *        v  v          (5)        v      v
 28    * (1) -> BUSY_STATE   ----> FINISHING_STATE
 29    *                                | (6)
 30    *                                v
 31    *                           FINISHED_STATE
 32    *    \_____________________________________/
 33    *                    | (7)
 34    *                    v
 35    *               CLOSED_STATE
 36    *
 37    * (1) If we should produce a header we start in INIT_STATE, otherwise
 38    *     we start in BUSY_STATE.
 39    * (2) A dictionary may be set only when we are in INIT_STATE, then
 40    *     we change the state as indicated.
 41    * (3) Whether a dictionary is set or not, on the first call of deflate
 42    *     we change to BUSY_STATE.
 43    * (4) -- intentionally left blank -- :)
 44    * (5) FINISHING_STATE is entered, when flush() is called to indicate that
 45    *     there is no more INPUT.  There are also states indicating, that
 46    *     the header wasn't written yet.
 47    * (6) FINISHED_STATE is entered, when everything has been flushed to the
 48    *     internal pending output buffer.
 49    * (7) At any time (7)
 50    *
 51    */
 52    #endregion
 53    #region Public Constants
 54    /// <summary>
 55    /// The best and slowest compression level.  This tries to find very
 56    /// long and distant string repetitions.
 57    /// </summary>
 58    public const int BEST_COMPRESSION = 9;
 59
 60    /// <summary>
 61    /// The worst but fastest compression level.
 62    /// </summary>
 63    public const int BEST_SPEED = 1;
 64
 65    /// <summary>
 66    /// The default compression level.
 67    /// </summary>
 68    public const int DEFAULT_COMPRESSION = -1;
 69
 70    /// <summary>
 71    /// This level won't compress at all but output uncompressed blocks.
 72    /// </summary>
 73    public const int NO_COMPRESSION = 0;
 74
 75    /// <summary>
 76    /// The compression method.  This is the only method supported so far.
 77    /// There is no need to use this constant at all.
 78    /// </summary>
 79    public const int DEFLATED = 8;
 80    #endregion
 81    #region Local Constants
 82    private const int IS_SETDICT = 0x01;
 83    private const int IS_FLUSHING = 0x04;
 84    private const int IS_FINISHING = 0x08;
 85
 86    private const int INIT_STATE = 0x00;
 87    private const int SETDICT_STATE = 0x01;
 88    //    private static  int INIT_FINISHING_STATE    = 0x08;
 89    //    private static  int SETDICT_FINISHING_STATE = 0x09;
 90    private const int BUSY_STATE = 0x10;
 91    private const int FLUSHING_STATE = 0x14;
 92    private const int FINISHING_STATE = 0x1c;
 93    private const int FINISHED_STATE = 0x1e;
 94    private const int CLOSED_STATE = 0x7f;
 95    #endregion
 96    #region Constructors
 97    /// <summary>
 98    /// Creates a new deflater with default compression level.
 99    /// </summary>
 4100    public Deflater() : this(DEFAULT_COMPRESSION, false)
 101    {
 102
 4103    }
 104
 105    /// <summary>
 106    /// Creates a new deflater with given compression level.
 107    /// </summary>
 108    /// <param name="level">
 109    /// the compression level, a value between NO_COMPRESSION
 110    /// and BEST_COMPRESSION, or DEFAULT_COMPRESSION.
 111    /// </param>
 112    /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
 0113    public Deflater(int level) : this(level, false)
 114    {
 115
 0116    }
 117
 118    /// <summary>
 119    /// Creates a new deflater with given compression level.
 120    /// </summary>
 121    /// <param name="level">
 122    /// the compression level, a value between NO_COMPRESSION
 123    /// and BEST_COMPRESSION.
 124    /// </param>
 125    /// <param name="noZlibHeaderOrFooter">
 126    /// true, if we should suppress the Zlib/RFC1950 header at the
 127    /// beginning and the adler checksum at the end of the output.  This is
 128    /// useful for the GZIP/PKZIP formats.
 129    /// </param>
 130    /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
 273131    public Deflater(int level, bool noZlibHeaderOrFooter)
 132    {
 273133       if (level == DEFAULT_COMPRESSION) {
 100134        level = 6;
 273135       } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
 0136        throw new ArgumentOutOfRangeException(nameof(level));
 137      }
 138
 273139      pending = new DeflaterPending();
 273140      engine = new DeflaterEngine(pending);
 273141      this.noZlibHeaderOrFooter = noZlibHeaderOrFooter;
 273142      SetStrategy(DeflateStrategy.Default);
 273143      SetLevel(level);
 273144      Reset();
 273145    }
 146    #endregion
 147
 148    /// <summary>
 149    /// Resets the deflater.  The deflater acts afterwards as if it was
 150    /// just created with the same compression level and strategy as it
 151    /// had before.
 152    /// </summary>
 153    public void Reset()
 154    {
 392155       state = (noZlibHeaderOrFooter ? BUSY_STATE : INIT_STATE);
 392156      totalOut = 0;
 392157      pending.Reset();
 392158      engine.Reset();
 392159    }
 160
 161    /// <summary>
 162    /// Gets the current adler checksum of the data that was processed so far.
 163    /// </summary>
 164    public int Adler {
 165      get {
 0166        return engine.Adler;
 167      }
 168    }
 169
 170    /// <summary>
 171    /// Gets the number of input bytes processed so far.
 172    /// </summary>
 173    public long TotalIn {
 174      get {
 9175        return engine.TotalIn;
 176      }
 177    }
 178
 179    /// <summary>
 180    /// Gets the number of output bytes so far.
 181    /// </summary>
 182    public long TotalOut {
 183      get {
 119184        return totalOut;
 185      }
 186    }
 187
 188    /// <summary>
 189    /// Flushes the current input block.  Further calls to deflate() will
 190    /// produce enough output to inflate everything in the current input
 191    /// block.  This is not part of Sun's JDK so I have made it package
 192    /// private.  It is used by DeflaterOutputStream to implement
 193    /// flush().
 194    /// </summary>
 195    public void Flush()
 196    {
 30197      state |= IS_FLUSHING;
 30198    }
 199
 200    /// <summary>
 201    /// Finishes the deflater with the current input block.  It is an error
 202    /// to give more input after this method was called.  This method must
 203    /// be called to force all bytes to be flushed.
 204    /// </summary>
 205    public void Finish()
 206    {
 325207      state |= (IS_FLUSHING | IS_FINISHING);
 325208    }
 209
 210    /// <summary>
 211    /// Returns true if the stream was finished and no more output bytes
 212    /// are available.
 213    /// </summary>
 214    public bool IsFinished {
 215      get {
 1898216        return (state == FINISHED_STATE) && pending.IsFlushed;
 217      }
 218    }
 219
 220    /// <summary>
 221    /// Returns true, if the input buffer is empty.
 222    /// You should then call setInput().
 223    /// NOTE: This method can also return true when the stream
 224    /// was finished.
 225    /// </summary>
 226    public bool IsNeedingInput {
 227      get {
 16258228        return engine.NeedsInput();
 229      }
 230    }
 231
 232    /// <summary>
 233    /// Sets the data which should be compressed next.  This should be only
 234    /// called when needsInput indicates that more input is needed.
 235    /// If you call setInput when needsInput() returns false, the
 236    /// previous input that is still pending will be thrown away.
 237    /// The given byte array should not be changed, before needsInput() returns
 238    /// true again.
 239    /// This call is equivalent to <code>setInput(input, 0, input.length)</code>.
 240    /// </summary>
 241    /// <param name="input">
 242    /// the buffer containing the input data.
 243    /// </param>
 244    /// <exception cref="System.InvalidOperationException">
 245    /// if the buffer was finished() or ended().
 246    /// </exception>
 247    public void SetInput(byte[] input)
 248    {
 0249      SetInput(input, 0, input.Length);
 0250    }
 251
 252    /// <summary>
 253    /// Sets the data which should be compressed next.  This should be
 254    /// only called when needsInput indicates that more input is needed.
 255    /// The given byte array should not be changed, before needsInput() returns
 256    /// true again.
 257    /// </summary>
 258    /// <param name="input">
 259    /// the buffer containing the input data.
 260    /// </param>
 261    /// <param name="offset">
 262    /// the start of the data.
 263    /// </param>
 264    /// <param name="count">
 265    /// the number of data bytes of input.
 266    /// </param>
 267    /// <exception cref="System.InvalidOperationException">
 268    /// if the buffer was Finish()ed or if previous input is still pending.
 269    /// </exception>
 270    public void SetInput(byte[] input, int offset, int count)
 271    {
 4479272       if ((state & IS_FINISHING) != 0) {
 0273        throw new InvalidOperationException("Finish() already called");
 274      }
 4479275      engine.SetInput(input, offset, count);
 4479276    }
 277
 278    /// <summary>
 279    /// Sets the compression level.  There is no guarantee of the exact
 280    /// position of the change, but if you call this when needsInput is
 281    /// true the change of compression level will occur somewhere near
 282    /// before the end of the so far given input.
 283    /// </summary>
 284    /// <param name="level">
 285    /// the new compression level.
 286    /// </param>
 287    public void SetLevel(int level)
 288    {
 447289       if (level == DEFAULT_COMPRESSION) {
 59290        level = 6;
 447291       } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
 0292        throw new ArgumentOutOfRangeException(nameof(level));
 293      }
 294
 447295       if (this.level != level) {
 327296        this.level = level;
 327297        engine.SetLevel(level);
 298      }
 447299    }
 300
 301    /// <summary>
 302    /// Get current compression level
 303    /// </summary>
 304    /// <returns>Returns the current compression level</returns>
 305    public int GetLevel()
 306    {
 3307      return level;
 308    }
 309
 310    /// <summary>
 311    /// Sets the compression strategy. Strategy is one of
 312    /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED.  For the exact
 313    /// position where the strategy is changed, the same as for
 314    /// SetLevel() applies.
 315    /// </summary>
 316    /// <param name="strategy">
 317    /// The new compression strategy.
 318    /// </param>
 319    public void SetStrategy(DeflateStrategy strategy)
 320    {
 273321      engine.Strategy = strategy;
 273322    }
 323
 324    /// <summary>
 325    /// Deflates the current input block with to the given array.
 326    /// </summary>
 327    /// <param name="output">
 328    /// The buffer where compressed data is stored
 329    /// </param>
 330    /// <returns>
 331    /// The number of compressed bytes added to the output, or 0 if either
 332    /// IsNeedingInput() or IsFinished returns true or length is zero.
 333    /// </returns>
 334    public int Deflate(byte[] output)
 335    {
 0336      return Deflate(output, 0, output.Length);
 337    }
 338
 339    /// <summary>
 340    /// Deflates the current input block to the given array.
 341    /// </summary>
 342    /// <param name="output">
 343    /// Buffer to store the compressed data.
 344    /// </param>
 345    /// <param name="offset">
 346    /// Offset into the output array.
 347    /// </param>
 348    /// <param name="length">
 349    /// The maximum number of bytes that may be stored.
 350    /// </param>
 351    /// <returns>
 352    /// The number of compressed bytes added to the output, or 0 if either
 353    /// needsInput() or finished() returns true or length is zero.
 354    /// </returns>
 355    /// <exception cref="System.InvalidOperationException">
 356    /// If Finish() was previously called.
 357    /// </exception>
 358    /// <exception cref="System.ArgumentOutOfRangeException">
 359    /// If offset or length don't match the array length.
 360    /// </exception>
 361    public int Deflate(byte[] output, int offset, int length)
 362    {
 12717363      int origLength = length;
 364
 12717365       if (state == CLOSED_STATE) {
 0366        throw new InvalidOperationException("Deflater closed");
 367      }
 368
 12717369       if (state < BUSY_STATE) {
 370        // output header
 14371        int header = (DEFLATED +
 14372          ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8;
 14373        int level_flags = (level - 1) >> 1;
 14374         if (level_flags < 0 || level_flags > 3) {
 2375          level_flags = 3;
 376        }
 14377        header |= level_flags << 6;
 14378         if ((state & IS_SETDICT) != 0) {
 379          // Dictionary was set
 0380          header |= DeflaterConstants.PRESET_DICT;
 381        }
 14382        header += 31 - (header % 31);
 383
 14384        pending.WriteShortMSB(header);
 14385         if ((state & IS_SETDICT) != 0) {
 0386          int chksum = engine.Adler;
 0387          engine.ResetAdler();
 0388          pending.WriteShortMSB(chksum >> 16);
 0389          pending.WriteShortMSB(chksum & 0xffff);
 390        }
 391
 14392        state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));
 393      }
 394
 395      for (;;) {
 13248396        int count = pending.Flush(output, offset, length);
 13248397        offset += count;
 13248398        totalOut += count;
 13248399        length -= count;
 400
 13248401         if (length == 0 || state == FINISHED_STATE) {
 402          break;
 403        }
 404
 4878405         if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) {
 4652406           switch (state) {
 407            case BUSY_STATE:
 408              // We need more input now
 4347409              return origLength - length;
 410            case FLUSHING_STATE:
 0411               if (level != NO_COMPRESSION) {
 412                /* We have to supply some lookahead.  8 bit lookahead
 413                 * is needed by the zlib inflater, and we must fill
 414                 * the next byte, so that all bits are flushed.
 415                 */
 0416                int neededbits = 8 + ((-pending.BitCount) & 7);
 0417                 while (neededbits > 0) {
 418                  /* write a static tree block consisting solely of
 419                   * an EOF:
 420                   */
 0421                  pending.WriteBits(2, 10);
 0422                  neededbits -= 10;
 423                }
 424              }
 0425              state = BUSY_STATE;
 0426              break;
 427            case FINISHING_STATE:
 305428              pending.AlignToByte();
 429
 430              // Compressed data is complete.  Write footer information if required.
 305431               if (!noZlibHeaderOrFooter) {
 14432                int adler = engine.Adler;
 14433                pending.WriteShortMSB(adler >> 16);
 14434                pending.WriteShortMSB(adler & 0xffff);
 435              }
 305436              state = FINISHED_STATE;
 305437              break;
 438          }
 439        }
 440      }
 8370441      return origLength - length;
 442    }
 443
 444    /// <summary>
 445    /// Sets the dictionary which should be used in the deflate process.
 446    /// This call is equivalent to <code>setDictionary(dict, 0, dict.Length)</code>.
 447    /// </summary>
 448    /// <param name="dictionary">
 449    /// the dictionary.
 450    /// </param>
 451    /// <exception cref="System.InvalidOperationException">
 452    /// if SetInput () or Deflate () were already called or another dictionary was already set.
 453    /// </exception>
 454    public void SetDictionary(byte[] dictionary)
 455    {
 0456      SetDictionary(dictionary, 0, dictionary.Length);
 0457    }
 458
 459    /// <summary>
 460    /// Sets the dictionary which should be used in the deflate process.
 461    /// The dictionary is a byte array containing strings that are
 462    /// likely to occur in the data which should be compressed.  The
 463    /// dictionary is not stored in the compressed output, only a
 464    /// checksum.  To decompress the output you need to supply the same
 465    /// dictionary again.
 466    /// </summary>
 467    /// <param name="dictionary">
 468    /// The dictionary data
 469    /// </param>
 470    /// <param name="index">
 471    /// The index where dictionary information commences.
 472    /// </param>
 473    /// <param name="count">
 474    /// The number of bytes in the dictionary.
 475    /// </param>
 476    /// <exception cref="System.InvalidOperationException">
 477    /// If SetInput () or Deflate() were already called or another dictionary was already set.
 478    /// </exception>
 479    public void SetDictionary(byte[] dictionary, int index, int count)
 480    {
 0481       if (state != INIT_STATE) {
 0482        throw new InvalidOperationException();
 483      }
 484
 0485      state = SETDICT_STATE;
 0486      engine.SetDictionary(dictionary, index, count);
 0487    }
 488
 489    #region Instance Fields
 490    /// <summary>
 491    /// Compression level.
 492    /// </summary>
 493    int level;
 494
 495    /// <summary>
 496    /// If true no Zlib/RFC1950 headers or footers are generated
 497    /// </summary>
 498    bool noZlibHeaderOrFooter;
 499
 500    /// <summary>
 501    /// The current state.
 502    /// </summary>
 503    int state;
 504
 505    /// <summary>
 506    /// The total bytes of output written.
 507    /// </summary>
 508    long totalOut;
 509
 510    /// <summary>
 511    /// The pending output.
 512    /// </summary>
 513    DeflaterPending pending;
 514
 515    /// <summary>
 516    /// The deflater engine.
 517    /// </summary>
 518    DeflaterEngine engine;
 519    #endregion
 520  }
 521}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DeflaterConstants.htm b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterConstants.htm new file mode 100644 index 000000000..5ff6a3b35 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterConstants.htm @@ -0,0 +1,187 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterConstants.cs
Covered lines:6
Uncovered lines:0
Coverable lines:6
Total lines:146
Line coverage:100%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.cctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterConstants.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Zip.Compression
 4{
 5  /// <summary>
 6  /// This class contains constants used for deflation.
 7  /// </summary>
 8  public static class DeflaterConstants
 9  {
 10    /// <summary>
 11    /// Set to true to enable debugging
 12    /// </summary>
 13    public const bool DEBUGGING = false;
 14
 15    /// <summary>
 16    /// Written to Zip file to identify a stored block
 17    /// </summary>
 18    public const int STORED_BLOCK = 0;
 19
 20    /// <summary>
 21    /// Identifies static tree in Zip file
 22    /// </summary>
 23    public const int STATIC_TREES = 1;
 24
 25    /// <summary>
 26    /// Identifies dynamic tree in Zip file
 27    /// </summary>
 28    public const int DYN_TREES = 2;
 29
 30    /// <summary>
 31    /// Header flag indicating a preset dictionary for deflation
 32    /// </summary>
 33    public const int PRESET_DICT = 0x20;
 34
 35    /// <summary>
 36    /// Sets internal buffer sizes for Huffman encoding
 37    /// </summary>
 38    public const int DEFAULT_MEM_LEVEL = 8;
 39
 40    /// <summary>
 41    /// Internal compression engine constant
 42    /// </summary>
 43    public const int MAX_MATCH = 258;
 44
 45    /// <summary>
 46    /// Internal compression engine constant
 47    /// </summary>
 48    public const int MIN_MATCH = 3;
 49
 50    /// <summary>
 51    /// Internal compression engine constant
 52    /// </summary>
 53    public const int MAX_WBITS = 15;
 54
 55    /// <summary>
 56    /// Internal compression engine constant
 57    /// </summary>
 58    public const int WSIZE = 1 << MAX_WBITS;
 59
 60    /// <summary>
 61    /// Internal compression engine constant
 62    /// </summary>
 63    public const int WMASK = WSIZE - 1;
 64
 65    /// <summary>
 66    /// Internal compression engine constant
 67    /// </summary>
 68    public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
 69
 70    /// <summary>
 71    /// Internal compression engine constant
 72    /// </summary>
 73    public const int HASH_SIZE = 1 << HASH_BITS;
 74
 75    /// <summary>
 76    /// Internal compression engine constant
 77    /// </summary>
 78    public const int HASH_MASK = HASH_SIZE - 1;
 79
 80    /// <summary>
 81    /// Internal compression engine constant
 82    /// </summary>
 83    public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
 84
 85    /// <summary>
 86    /// Internal compression engine constant
 87    /// </summary>
 88    public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
 89
 90    /// <summary>
 91    /// Internal compression engine constant
 92    /// </summary>
 93    public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
 94
 95    /// <summary>
 96    /// Internal compression engine constant
 97    /// </summary>
 98    public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);
 99
 100    /// <summary>
 101    /// Internal compression engine constant
 102    /// </summary>
 1103    public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE - 5);
 104
 105    /// <summary>
 106    /// Internal compression engine constant
 107    /// </summary>
 108    public const int DEFLATE_STORED = 0;
 109
 110    /// <summary>
 111    /// Internal compression engine constant
 112    /// </summary>
 113    public const int DEFLATE_FAST = 1;
 114
 115    /// <summary>
 116    /// Internal compression engine constant
 117    /// </summary>
 118    public const int DEFLATE_SLOW = 2;
 119
 120    /// <summary>
 121    /// Internal compression engine constant
 122    /// </summary>
 1123    public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 };
 124
 125    /// <summary>
 126    /// Internal compression engine constant
 127    /// </summary>
 1128    public static int[] MAX_LAZY = { 0, 4, 5, 6, 4, 16, 16, 32, 128, 258 };
 129
 130    /// <summary>
 131    /// Internal compression engine constant
 132    /// </summary>
 1133    public static int[] NICE_LENGTH = { 0, 8, 16, 32, 16, 32, 128, 128, 258, 258 };
 134
 135    /// <summary>
 136    /// Internal compression engine constant
 137    /// </summary>
 1138    public static int[] MAX_CHAIN = { 0, 4, 8, 32, 16, 32, 128, 256, 1024, 4096 };
 139
 140    /// <summary>
 141    /// Internal compression engine constant
 142    /// </summary>
 1143    public static int[] COMPR_FUNC = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
 144
 145  }
 146}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DeflaterEngine.htm b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterEngine.htm new file mode 100644 index 000000000..078abf45e --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterEngine.htm @@ -0,0 +1,869 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterEngine.cs
Covered lines:238
Uncovered lines:37
Coverable lines:275
Total lines:812
Line coverage:86.5%
Branch coverage:84.4%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
Deflate(...)691.6785.71
SetInput(...)766.6753.85
NeedsInput()1100100
SetDictionary(...)400
Reset()3100100
ResetAdler()100
SetLevel(...)1165.3863.16
FillWindow()6100100
UpdateHash()1100100
InsertString()1100100
SlideWindow()7100100
FindLongestMatch(...)2010094.87
DeflateStored(...)8100100
DeflateFast(...)1893.9487.88
DeflateSlow(...)2510093.33
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterEngine.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using ICSharpCode.SharpZipLib.Checksum;
 3
 4namespace ICSharpCode.SharpZipLib.Zip.Compression
 5{
 6  /// <summary>
 7  /// Strategies for deflater
 8  /// </summary>
 9  public enum DeflateStrategy
 10  {
 11    /// <summary>
 12    /// The default strategy
 13    /// </summary>
 14    Default = 0,
 15
 16    /// <summary>
 17    /// This strategy will only allow longer string repetitions.  It is
 18    /// useful for random data with a small character set.
 19    /// </summary>
 20    Filtered = 1,
 21
 22
 23    /// <summary>
 24    /// This strategy will not look for string repetitions at all.  It
 25    /// only encodes with Huffman trees (which means, that more common
 26    /// characters get a smaller encoding.
 27    /// </summary>
 28    HuffmanOnly = 2
 29  }
 30
 31  // DEFLATE ALGORITHM:
 32  //
 33  // The uncompressed stream is inserted into the window array.  When
 34  // the window array is full the first half is thrown away and the
 35  // second half is copied to the beginning.
 36  //
 37  // The head array is a hash table.  Three characters build a hash value
 38  // and they the value points to the corresponding index in window of
 39  // the last string with this hash.  The prev array implements a
 40  // linked list of matches with the same hash: prev[index & WMASK] points
 41  // to the previous index with the same hash.
 42  //
 43
 44
 45  /// <summary>
 46  /// Low level compression engine for deflate algorithm which uses a 32K sliding window
 47  /// with secondary compression from Huffman/Shannon-Fano codes.
 48  /// </summary>
 49  public class DeflaterEngine
 50  {
 51    #region Constants
 52    const int TooFar = 4096;
 53    #endregion
 54
 55    #region Constructors
 56    /// <summary>
 57    /// Construct instance with pending buffer
 58    /// </summary>
 59    /// <param name="pending">
 60    /// Pending buffer to use
 61    /// </param>>
 27362    public DeflaterEngine(DeflaterPending pending)
 63    {
 27364      this.pending = pending;
 27365      huffman = new DeflaterHuffman(pending);
 27366      adler = new Adler32();
 67
 27368      window = new byte[2 * DeflaterConstants.WSIZE];
 27369      head = new short[DeflaterConstants.HASH_SIZE];
 27370      prev = new short[DeflaterConstants.WSIZE];
 71
 72      // We start at index 1, to avoid an implementation deficiency, that
 73      // we cannot build a repeat pattern at index 0.
 27374      blockStart = strstart = 1;
 27375    }
 76
 77    #endregion
 78
 79    /// <summary>
 80    /// Deflate drives actual compression of data
 81    /// </summary>
 82    /// <param name="flush">True to flush input buffers</param>
 83    /// <param name="finish">Finish deflation with the current input.</param>
 84    /// <returns>Returns true if progress has been made.</returns>
 85    public bool Deflate(bool flush, bool finish)
 86    {
 87      bool progress;
 88      do {
 914089        FillWindow();
 914090        bool canFlush = flush && (inputOff == inputEnd);
 91
 92#if DebugDeflation
 93        if (DeflaterConstants.DEBUGGING) {
 94          Console.WriteLine("window: [" + blockStart + "," + strstart + ","
 95                + lookahead + "], " + compressionFunction + "," + canFlush);
 96        }
 97#endif
 914098         switch (compressionFunction) {
 99          case DeflaterConstants.DEFLATE_STORED:
 1373100            progress = DeflateStored(canFlush, finish);
 1373101            break;
 102          case DeflaterConstants.DEFLATE_FAST:
 3236103            progress = DeflateFast(canFlush, finish);
 3236104            break;
 105          case DeflaterConstants.DEFLATE_SLOW:
 4531106            progress = DeflateSlow(canFlush, finish);
 4531107            break;
 108          default:
 0109            throw new InvalidOperationException("unknown compressionFunction");
 110        }
 9140111       } while (pending.IsFlushed && progress); // repeat while we have no pending output and progress was made
 4878112      return progress;
 113    }
 114
 115    /// <summary>
 116    /// Sets input data to be deflated.  Should only be called when <code>NeedsInput()</code>
 117    /// returns true
 118    /// </summary>
 119    /// <param name="buffer">The buffer containing input data.</param>
 120    /// <param name="offset">The offset of the first byte of data.</param>
 121    /// <param name="count">The number of bytes of data to use as input.</param>
 122    public void SetInput(byte[] buffer, int offset, int count)
 123    {
 4479124       if (buffer == null) {
 0125        throw new ArgumentNullException(nameof(buffer));
 126      }
 127
 4479128       if (offset < 0) {
 0129        throw new ArgumentOutOfRangeException(nameof(offset));
 130      }
 131
 4479132       if (count < 0) {
 0133        throw new ArgumentOutOfRangeException(nameof(count));
 134      }
 135
 4479136       if (inputOff < inputEnd) {
 0137        throw new InvalidOperationException("Old input was not completely processed");
 138      }
 139
 4479140      int end = offset + count;
 141
 142      /* We want to throw an ArrayIndexOutOfBoundsException early.  The
 143      * check is very tricky: it also handles integer wrap around.
 144      */
 4479145       if ((offset > end) || (end > buffer.Length)) {
 0146        throw new ArgumentOutOfRangeException(nameof(count));
 147      }
 148
 4479149      inputBuf = buffer;
 4479150      inputOff = offset;
 4479151      inputEnd = end;
 4479152    }
 153
 154    /// <summary>
 155    /// Determines if more <see cref="SetInput">input</see> is needed.
 156    /// </summary>
 157    /// <returns>Return true if input is needed via <see cref="SetInput">SetInput</see></returns>
 158    public bool NeedsInput()
 159    {
 16258160      return (inputEnd == inputOff);
 161    }
 162
 163    /// <summary>
 164    /// Set compression dictionary
 165    /// </summary>
 166    /// <param name="buffer">The buffer containing the dictionary data</param>
 167    /// <param name="offset">The offset in the buffer for the first byte of data</param>
 168    /// <param name="length">The length of the dictionary data.</param>
 169    public void SetDictionary(byte[] buffer, int offset, int length)
 170    {
 171#if DebugDeflation
 172      if (DeflaterConstants.DEBUGGING && (strstart != 1) )
 173      {
 174        throw new InvalidOperationException("strstart not 1");
 175      }
 176#endif
 0177      adler.Update(buffer, offset, length);
 0178       if (length < DeflaterConstants.MIN_MATCH) {
 0179        return;
 180      }
 181
 0182       if (length > DeflaterConstants.MAX_DIST) {
 0183        offset += length - DeflaterConstants.MAX_DIST;
 0184        length = DeflaterConstants.MAX_DIST;
 185      }
 186
 0187      System.Array.Copy(buffer, offset, window, strstart, length);
 188
 0189      UpdateHash();
 0190      --length;
 0191       while (--length > 0) {
 0192        InsertString();
 0193        strstart++;
 194      }
 0195      strstart += 2;
 0196      blockStart = strstart;
 0197    }
 198
 199    /// <summary>
 200    /// Reset internal state
 201    /// </summary>
 202    public void Reset()
 203    {
 392204      huffman.Reset();
 392205      adler.Reset();
 392206      blockStart = strstart = 1;
 392207      lookahead = 0;
 392208      totalIn = 0;
 392209      prevAvailable = false;
 392210      matchLen = DeflaterConstants.MIN_MATCH - 1;
 211
 25690896212       for (int i = 0; i < DeflaterConstants.HASH_SIZE; i++) {
 12845056213        head[i] = 0;
 214      }
 215
 25690896216       for (int i = 0; i < DeflaterConstants.WSIZE; i++) {
 12845056217        prev[i] = 0;
 218      }
 392219    }
 220
 221    /// <summary>
 222    /// Reset Adler checksum
 223    /// </summary>
 224    public void ResetAdler()
 225    {
 0226      adler.Reset();
 0227    }
 228
 229    /// <summary>
 230    /// Get current value of Adler checksum
 231    /// </summary>
 232    public int Adler {
 233      get {
 14234        return unchecked((int)adler.Value);
 235      }
 236    }
 237
 238    /// <summary>
 239    /// Total data processed
 240    /// </summary>
 241    public long TotalIn {
 242      get {
 9243        return totalIn;
 244      }
 245    }
 246
 247    /// <summary>
 248    /// Get/set the <see cref="DeflateStrategy">deflate strategy</see>
 249    /// </summary>
 250    public DeflateStrategy Strategy {
 251      get {
 0252        return strategy;
 253      }
 254      set {
 273255        strategy = value;
 273256      }
 257    }
 258
 259    /// <summary>
 260    /// Set the deflate level (0-9)
 261    /// </summary>
 262    /// <param name="level">The value to set the level to.</param>
 263    public void SetLevel(int level)
 264    {
 327265       if ((level < 0) || (level > 9)) {
 0266        throw new ArgumentOutOfRangeException(nameof(level));
 267      }
 268
 327269      goodLength = DeflaterConstants.GOOD_LENGTH[level];
 327270      max_lazy = DeflaterConstants.MAX_LAZY[level];
 327271      niceLength = DeflaterConstants.NICE_LENGTH[level];
 327272      max_chain = DeflaterConstants.MAX_CHAIN[level];
 273
 327274       if (DeflaterConstants.COMPR_FUNC[level] != compressionFunction) {
 275
 276#if DebugDeflation
 277        if (DeflaterConstants.DEBUGGING) {
 278           Console.WriteLine("Change from " + compressionFunction + " to "
 279                      + DeflaterConstants.COMPR_FUNC[level]);
 280        }
 281#endif
 309282         switch (compressionFunction) {
 283          case DeflaterConstants.DEFLATE_STORED:
 272284             if (strstart > blockStart) {
 0285              huffman.FlushStoredBlock(window, blockStart,
 0286                strstart - blockStart, false);
 0287              blockStart = strstart;
 288            }
 272289            UpdateHash();
 272290            break;
 291
 292          case DeflaterConstants.DEFLATE_FAST:
 6293             if (strstart > blockStart) {
 0294              huffman.FlushBlock(window, blockStart, strstart - blockStart,
 0295                false);
 0296              blockStart = strstart;
 297            }
 0298            break;
 299
 300          case DeflaterConstants.DEFLATE_SLOW:
 31301             if (prevAvailable) {
 0302              huffman.TallyLit(window[strstart - 1] & 0xff);
 303            }
 31304             if (strstart > blockStart) {
 0305              huffman.FlushBlock(window, blockStart, strstart - blockStart, false);
 0306              blockStart = strstart;
 307            }
 31308            prevAvailable = false;
 31309            matchLen = DeflaterConstants.MIN_MATCH - 1;
 310            break;
 311        }
 309312        compressionFunction = DeflaterConstants.COMPR_FUNC[level];
 313      }
 327314    }
 315
 316    /// <summary>
 317    /// Fill the window
 318    /// </summary>
 319    public void FillWindow()
 320    {
 321      /* If the window is almost full and there is insufficient lookahead,
 322       * move the upper half to the lower one to make room in the upper half.
 323       */
 9140324       if (strstart >= DeflaterConstants.WSIZE + DeflaterConstants.MAX_DIST) {
 20325        SlideWindow();
 326      }
 327
 328      /* If there is not enough lookahead, but still some input left,
 329       * read in the input
 330       */
 13659331       while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd) {
 4519332        int more = 2 * DeflaterConstants.WSIZE - lookahead - strstart;
 333
 4519334         if (more > inputEnd - inputOff) {
 4479335          more = inputEnd - inputOff;
 336        }
 337
 4519338        System.Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);
 4519339        adler.Update(inputBuf, inputOff, more);
 340
 4519341        inputOff += more;
 4519342        totalIn += more;
 4519343        lookahead += more;
 344      }
 345
 9140346       if (lookahead >= DeflaterConstants.MIN_MATCH) {
 8381347        UpdateHash();
 348      }
 9140349    }
 350
 351    void UpdateHash()
 352    {
 353      /*
 354            if (DEBUGGING) {
 355              Console.WriteLine("updateHash: "+strstart);
 356            }
 357      */
 8653358      ins_h = (window[strstart] << DeflaterConstants.HASH_SHIFT) ^ window[strstart + 1];
 8653359    }
 360
 361    /// <summary>
 362    /// Inserts the current string in the head hash and returns the previous
 363    /// value for this hash.
 364    /// </summary>
 365    /// <returns>The previous hash value</returns>
 366    int InsertString()
 367    {
 368      short match;
 3625693369      int hash = ((ins_h << DeflaterConstants.HASH_SHIFT) ^ window[strstart + (DeflaterConstants.MIN_MATCH - 1)]) & Defl
 370
 371#if DebugDeflation
 372      if (DeflaterConstants.DEBUGGING)
 373      {
 374        if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^
 375                  (window[strstart + 1] << HASH_SHIFT) ^
 376                  (window[strstart + 2])) & HASH_MASK)) {
 377            throw new SharpZipBaseException("hash inconsistent: " + hash + "/"
 378                        +window[strstart] + ","
 379                        +window[strstart + 1] + ","
 380                        +window[strstart + 2] + "," + HASH_SHIFT);
 381          }
 382      }
 383#endif
 3625693384      prev[strstart & DeflaterConstants.WMASK] = match = head[hash];
 3625693385      head[hash] = unchecked((short)strstart);
 3625693386      ins_h = hash;
 3625693387      return match & 0xffff;
 388    }
 389
 390    void SlideWindow()
 391    {
 40392      Array.Copy(window, DeflaterConstants.WSIZE, window, 0, DeflaterConstants.WSIZE);
 40393      matchStart -= DeflaterConstants.WSIZE;
 40394      strstart -= DeflaterConstants.WSIZE;
 40395      blockStart -= DeflaterConstants.WSIZE;
 396
 397      // Slide the hash table (could be avoided with 32 bit values
 398      // at the expense of memory usage).
 2621520399       for (int i = 0; i < DeflaterConstants.HASH_SIZE; ++i) {
 1310720400        int m = head[i] & 0xffff;
 1310720401         head[i] = (short)(m >= DeflaterConstants.WSIZE ? (m - DeflaterConstants.WSIZE) : 0);
 402      }
 403
 404      // Slide the prev table.
 2621520405       for (int i = 0; i < DeflaterConstants.WSIZE; i++) {
 1310720406        int m = prev[i] & 0xffff;
 1310720407         prev[i] = (short)(m >= DeflaterConstants.WSIZE ? (m - DeflaterConstants.WSIZE) : 0);
 408      }
 40409    }
 410
 411    /// <summary>
 412    /// Find the best (longest) string in the window matching the
 413    /// string starting at strstart.
 414    ///
 415    /// Preconditions:
 416    /// <code>
 417    /// strstart + DeflaterConstants.MAX_MATCH &lt;= window.length.</code>
 418    /// </summary>
 419    /// <param name="curMatch"></param>
 420    /// <returns>True if a match greater than the minimum length is found</returns>
 421    bool FindLongestMatch(int curMatch)
 422    {
 1801927423      int chainLength = this.max_chain;
 1801927424      int niceLength = this.niceLength;
 1801927425      short[] prev = this.prev;
 1801927426      int scan = this.strstart;
 427      int match;
 1801927428      int best_end = this.strstart + matchLen;
 1801927429      int best_len = Math.Max(matchLen, DeflaterConstants.MIN_MATCH - 1);
 430
 1801927431      int limit = Math.Max(strstart - DeflaterConstants.MAX_DIST, 0);
 432
 1801927433      int strend = strstart + DeflaterConstants.MAX_MATCH - 1;
 1801927434      byte scan_end1 = window[best_end - 1];
 1801927435      byte scan_end = window[best_end];
 436
 437      // Do not waste too much time if we already have a good match:
 1801927438       if (best_len >= this.goodLength) {
 66439        chainLength >>= 2;
 440      }
 441
 442      /* Do not look for matches beyond the end of the input. This is necessary
 443      * to make deflate deterministic.
 444      */
 1801927445       if (niceLength > lookahead) {
 3257446        niceLength = lookahead;
 447      }
 448
 449#if DebugDeflation
 450
 451      if (DeflaterConstants.DEBUGGING && (strstart > 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD))
 452      {
 453        throw new InvalidOperationException("need lookahead");
 454      }
 455#endif
 456
 457      do {
 458
 459#if DebugDeflation
 460
 461        if (DeflaterConstants.DEBUGGING && (curMatch >= strstart) )
 462        {
 463          throw new InvalidOperationException("no future");
 464        }
 465#endif
 2700341466         if (window[curMatch + best_len] != scan_end ||
 2700341467          window[curMatch + best_len - 1] != scan_end1 ||
 2700341468          window[curMatch] != window[scan] ||
 2700341469          window[curMatch + 1] != window[scan + 1]) {
 470          continue;
 471        }
 472
 5274473        match = curMatch + 2;
 5274474        scan += 2;
 475
 476        /* We check for insufficient lookahead only every 8th comparison;
 477        * the 256th check will be made at strstart + 258.
 478        */
 9174479         while (
 9174480          window[++scan] == window[++match] &&
 9174481          window[++scan] == window[++match] &&
 9174482          window[++scan] == window[++match] &&
 9174483          window[++scan] == window[++match] &&
 9174484          window[++scan] == window[++match] &&
 9174485          window[++scan] == window[++match] &&
 9174486          window[++scan] == window[++match] &&
 9174487          window[++scan] == window[++match] &&
 9174488          (scan < strend)) {
 489          // Do nothing
 490        }
 491
 5274492         if (scan > best_end) {
 493#if DebugDeflation
 494          if (DeflaterConstants.DEBUGGING && (ins_h == 0) )
 495            Console.Error.WriteLine("Found match: " + curMatch + "-" + (scan - strstart));
 496#endif
 5212497          matchStart = curMatch;
 5212498          best_end = scan;
 5212499          best_len = scan - strstart;
 500
 5212501           if (best_len >= niceLength) {
 502            break;
 503          }
 504
 5136505          scan_end1 = window[best_end - 1];
 5136506          scan_end = window[best_end];
 507        }
 5198508        scan = strstart;
 2700265509       } while ((curMatch = (prev[curMatch & DeflaterConstants.WMASK] & 0xffff)) > limit && --chainLength != 0);
 510
 1801927511      matchLen = Math.Min(best_len, lookahead);
 1801927512      return matchLen >= DeflaterConstants.MIN_MATCH;
 513    }
 514
 515    bool DeflateStored(bool flush, bool finish)
 516    {
 1373517       if (!flush && (lookahead == 0)) {
 676518        return false;
 519      }
 520
 697521      strstart += lookahead;
 697522      lookahead = 0;
 523
 697524      int storedLength = strstart - blockStart;
 525
 697526       if ((storedLength >= DeflaterConstants.MAX_BLOCK_SIZE) || // Block is full
 697527        (blockStart < DeflaterConstants.WSIZE && storedLength >= DeflaterConstants.MAX_DIST) ||   // Block may move out 
 697528        flush) {
 21529        bool lastBlock = finish;
 21530         if (storedLength > DeflaterConstants.MAX_BLOCK_SIZE) {
 2531          storedLength = DeflaterConstants.MAX_BLOCK_SIZE;
 2532          lastBlock = false;
 533        }
 534
 535#if DebugDeflation
 536        if (DeflaterConstants.DEBUGGING)
 537        {
 538           Console.WriteLine("storedBlock[" + storedLength + "," + lastBlock + "]");
 539        }
 540#endif
 541
 21542        huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock);
 21543        blockStart += storedLength;
 21544        return !lastBlock;
 545      }
 676546      return true;
 547    }
 548
 549    bool DeflateFast(bool flush, bool finish)
 550    {
 3236551       if (lookahead < DeflaterConstants.MIN_LOOKAHEAD && !flush) {
 1526552        return false;
 553      }
 554
 1597843555       while (lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) {
 1596259556         if (lookahead == 0) {
 557          // We are flushing everything
 30558          huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);
 30559          blockStart = strstart;
 30560          return false;
 561        }
 562
 1596229563         if (strstart > 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD) {
 564          /* slide window, as FindLongestMatch needs this.
 565           * This should only happen when flushing and the window
 566           * is almost full.
 567           */
 0568          SlideWindow();
 569        }
 570
 571        int hashHead;
 1596229572         if (lookahead >= DeflaterConstants.MIN_MATCH &&
 1596229573          (hashHead = InsertString()) != 0 &&
 1596229574          strategy != DeflateStrategy.HuffmanOnly &&
 1596229575          strstart - hashHead <= DeflaterConstants.MAX_DIST &&
 1596229576          FindLongestMatch(hashHead)) {
 577          // longestMatch sets matchStart and matchLen
 578#if DebugDeflation
 579          if (DeflaterConstants.DEBUGGING)
 580          {
 581            for (int i = 0 ; i < matchLen; i++) {
 582              if (window[strstart + i] != window[matchStart + i]) {
 583                throw new SharpZipBaseException("Match failure");
 584              }
 585            }
 586          }
 587#endif
 588
 2203589          bool full = huffman.TallyDist(strstart - matchStart, matchLen);
 590
 2203591          lookahead -= matchLen;
 2203592           if (matchLen <= max_lazy && lookahead >= DeflaterConstants.MIN_MATCH) {
 6608593             while (--matchLen > 0) {
 4408594              ++strstart;
 4408595              InsertString();
 596            }
 2200597            ++strstart;
 2200598          } else {
 3599            strstart += matchLen;
 3600             if (lookahead >= DeflaterConstants.MIN_MATCH - 1) {
 0601              UpdateHash();
 602            }
 603          }
 2203604          matchLen = DeflaterConstants.MIN_MATCH - 1;
 2203605           if (!full) {
 2203606            continue;
 607          }
 608        } else {
 609          // No match found
 1594026610          huffman.TallyLit(window[strstart] & 0xff);
 1594026611          ++strstart;
 1594026612          --lookahead;
 613        }
 614
 1594026615         if (huffman.IsFull()) {
 96616          bool lastBlock = finish && (lookahead == 0);
 96617          huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
 96618          blockStart = strstart;
 96619          return !lastBlock;
 620        }
 621      }
 1584622      return true;
 623    }
 624
 625    bool DeflateSlow(bool flush, bool finish)
 626    {
 4531627       if (lookahead < DeflaterConstants.MIN_LOOKAHEAD && !flush) {
 2145628        return false;
 629      }
 630
 2011632631       while (lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) {
 2009630632         if (lookahead == 0) {
 264633           if (prevAvailable) {
 205634            huffman.TallyLit(window[strstart - 1] & 0xff);
 635          }
 264636          prevAvailable = false;
 637
 638          // We are flushing everything
 639#if DebugDeflation
 640          if (DeflaterConstants.DEBUGGING && !flush)
 641          {
 642            throw new SharpZipBaseException("Not flushing, but no lookahead");
 643          }
 644#endif
 264645          huffman.FlushBlock(window, blockStart, strstart - blockStart,
 264646            finish);
 264647          blockStart = strstart;
 264648          return false;
 649        }
 650
 2009366651         if (strstart >= 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD) {
 652          /* slide window, as FindLongestMatch needs this.
 653           * This should only happen when flushing and the window
 654           * is almost full.
 655           */
 20656          SlideWindow();
 657        }
 658
 2009366659        int prevMatch = matchStart;
 2009366660        int prevLen = matchLen;
 2009366661         if (lookahead >= DeflaterConstants.MIN_MATCH) {
 662
 2008972663          int hashHead = InsertString();
 664
 2008972665           if (strategy != DeflateStrategy.HuffmanOnly &&
 2008972666            hashHead != 0 &&
 2008972667            strstart - hashHead <= DeflaterConstants.MAX_DIST &&
 2008972668            FindLongestMatch(hashHead)) {
 669
 670            // longestMatch sets matchStart and matchLen
 671
 672            // Discard match if too small and too far away
 3376673             if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == DeflaterConstants.MIN_MATCH && st
 2383674              matchLen = DeflaterConstants.MIN_MATCH - 1;
 675            }
 676          }
 677        }
 678
 679        // previous match was better
 2009366680         if ((prevLen >= DeflaterConstants.MIN_MATCH) && (matchLen <= prevLen)) {
 681#if DebugDeflation
 682          if (DeflaterConstants.DEBUGGING)
 683          {
 684             for (int i = 0 ; i < matchLen; i++) {
 685              if (window[strstart-1+i] != window[prevMatch + i])
 686               throw new SharpZipBaseException();
 687            }
 688          }
 689#endif
 625690          huffman.TallyDist(strstart - 1 - prevMatch, prevLen);
 625691          prevLen -= 2;
 692          do {
 16197693            strstart++;
 16197694            lookahead--;
 16197695             if (lookahead >= DeflaterConstants.MIN_MATCH) {
 16135696              InsertString();
 697            }
 16197698           } while (--prevLen > 0);
 699
 625700          strstart++;
 625701          lookahead--;
 625702          prevAvailable = false;
 625703          matchLen = DeflaterConstants.MIN_MATCH - 1;
 625704        } else {
 2008741705           if (prevAvailable) {
 2007911706            huffman.TallyLit(window[strstart - 1] & 0xff);
 707          }
 2008741708          prevAvailable = true;
 2008741709          strstart++;
 2008741710          lookahead--;
 711        }
 712
 2009366713         if (huffman.IsFull()) {
 120714          int len = strstart - blockStart;
 120715           if (prevAvailable) {
 120716            len--;
 717          }
 120718          bool lastBlock = (finish && (lookahead == 0) && !prevAvailable);
 120719          huffman.FlushBlock(window, blockStart, len, lastBlock);
 120720          blockStart += len;
 120721          return !lastBlock;
 722        }
 723      }
 2002724      return true;
 725    }
 726
 727    #region Instance Fields
 728
 729    // Hash index of string to be inserted
 730    int ins_h;
 731
 732    /// <summary>
 733    /// Hashtable, hashing three characters to an index for window, so
 734    /// that window[index]..window[index+2] have this hash code.
 735    /// Note that the array should really be unsigned short, so you need
 736    /// to and the values with 0xffff.
 737    /// </summary>
 738    short[] head;
 739
 740    /// <summary>
 741    /// <code>prev[index &amp; WMASK]</code> points to the previous index that has the
 742    /// same hash code as the string starting at index.  This way
 743    /// entries with the same hash code are in a linked list.
 744    /// Note that the array should really be unsigned short, so you need
 745    /// to and the values with 0xffff.
 746    /// </summary>
 747    short[] prev;
 748
 749    int matchStart;
 750    // Length of best match
 751    int matchLen;
 752    // Set if previous match exists
 753    bool prevAvailable;
 754    int blockStart;
 755
 756    /// <summary>
 757    /// Points to the current character in the window.
 758    /// </summary>
 759    int strstart;
 760
 761    /// <summary>
 762    /// lookahead is the number of characters starting at strstart in
 763    /// window that are valid.
 764    /// So window[strstart] until window[strstart+lookahead-1] are valid
 765    /// characters.
 766    /// </summary>
 767    int lookahead;
 768
 769    /// <summary>
 770    /// This array contains the part of the uncompressed stream that
 771    /// is of relevance.  The current character is indexed by strstart.
 772    /// </summary>
 773    byte[] window;
 774
 775    DeflateStrategy strategy;
 776    int max_chain, max_lazy, niceLength, goodLength;
 777
 778    /// <summary>
 779    /// The current compression function.
 780    /// </summary>
 781    int compressionFunction;
 782
 783    /// <summary>
 784    /// The input data for compression.
 785    /// </summary>
 786    byte[] inputBuf;
 787
 788    /// <summary>
 789    /// The total bytes of input read.
 790    /// </summary>
 791    long totalIn;
 792
 793    /// <summary>
 794    /// The offset into inputBuf, where input data starts.
 795    /// </summary>
 796    int inputOff;
 797
 798    /// <summary>
 799    /// The end offset of the input data.
 800    /// </summary>
 801    int inputEnd;
 802
 803    DeflaterPending pending;
 804    DeflaterHuffman huffman;
 805
 806    /// <summary>
 807    /// The adler checksum
 808    /// </summary>
 809    Adler32 adler;
 810    #endregion
 811  }
 812}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DeflaterHuffman.htm b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterHuffman.htm new file mode 100644 index 000000000..7251b9384 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterHuffman.htm @@ -0,0 +1,930 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterHuffman.cs
Covered lines:349
Uncovered lines:9
Coverable lines:358
Total lines:865
Line coverage:97.4%
Branch coverage:91.1%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.cctor()6100100
.ctor(...)1100100
Reset()1100100
SendAllTrees(...)2100100
CompressBlock()6100100
FlushStoredBlock(...)3100100
FlushBlock(...)1310085.71
IsFull()1100100
TallyLit(...)1100100
TallyDist(...)4100100
BitReverse(...)1100100
Lcode(...)3100100
Dcode(...)2100100
.ctor(...)1100100
Reset()2100100
WriteSymbol(...)1100100
CheckEmpty()300
SetStaticCodes(...)1100100
BuildCodes()4100100
BuildTree()2198.5197.44
GetEncodedLength()2100100
CalcBLFreq(...)10100100
WriteTree(...)1191.1885.71
BuildLength(...)1310084
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterHuffman.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Zip.Compression
 4{
 5  /// <summary>
 6  /// This is the DeflaterHuffman class.
 7  ///
 8  /// This class is <i>not</i> thread safe.  This is inherent in the API, due
 9  /// to the split of Deflate and SetInput.
 10  ///
 11  /// author of the original java version : Jochen Hoenicke
 12  /// </summary>
 13  public class DeflaterHuffman
 14  {
 15    const int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
 16    const int LITERAL_NUM = 286;
 17
 18    // Number of distance codes
 19    const int DIST_NUM = 30;
 20    // Number of codes used to transfer bit lengths
 21    const int BITLEN_NUM = 19;
 22
 23    // repeat previous bit length 3-6 times (2 bits of repeat count)
 24    const int REP_3_6 = 16;
 25    // repeat a zero length 3-10 times  (3 bits of repeat count)
 26    const int REP_3_10 = 17;
 27    // repeat a zero length 11-138 times  (7 bits of repeat count)
 28    const int REP_11_138 = 18;
 29
 30    const int EOF_SYMBOL = 256;
 31
 32    // The lengths of the bit length codes are sent in order of decreasing
 33    // probability, to avoid transmitting the lengths for unused bit length codes.
 134    static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
 35
 136    static readonly byte[] bit4Reverse = {
 137      0,
 138      8,
 139      4,
 140      12,
 141      2,
 142      10,
 143      6,
 144      14,
 145      1,
 146      9,
 147      5,
 148      13,
 149      3,
 150      11,
 151      7,
 152      15
 153    };
 54
 55    static short[] staticLCodes;
 56    static byte[] staticLLength;
 57    static short[] staticDCodes;
 58    static byte[] staticDLength;
 59
 60    class Tree
 61    {
 62      #region Instance Fields
 63      public short[] freqs;
 64
 65      public byte[] length;
 66
 67      public int minNumCodes;
 68
 69      public int numCodes;
 70
 71      short[] codes;
 72      readonly int[] bl_counts;
 73      readonly int maxLength;
 74      DeflaterHuffman dh;
 75      #endregion
 76
 77      #region Constructors
 81978      public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength)
 79      {
 81980        this.dh = dh;
 81981        this.minNumCodes = minCodes;
 81982        this.maxLength = maxLength;
 81983        freqs = new short[elems];
 81984        bl_counts = new int[maxLength];
 81985      }
 86
 87      #endregion
 88
 89      /// <summary>
 90      /// Resets the internal state of the tree
 91      /// </summary>
 92      public void Reset()
 93      {
 62394894         for (int i = 0; i < freqs.Length; i++) {
 30920595          freqs[i] = 0;
 96        }
 276997        codes = null;
 276998        length = null;
 276999      }
 100
 101      public void WriteSymbol(int code)
 102      {
 103        //        if (DeflaterConstants.DEBUGGING) {
 104        //          freqs[code]--;
 105        //          //      Console.Write("writeSymbol("+freqs.length+","+code+"): ");
 106        //        }
 8298107        dh.pending.WriteBits(codes[code] & 0xffff, length[code]);
 8298108      }
 109
 110      /// <summary>
 111      /// Check that all frequencies are zero
 112      /// </summary>
 113      /// <exception cref="SharpZipBaseException">
 114      /// At least one frequency is non-zero
 115      /// </exception>
 116      public void CheckEmpty()
 117      {
 0118        bool empty = true;
 0119         for (int i = 0; i < freqs.Length; i++) {
 0120          empty &= freqs[i] == 0;
 121        }
 122
 0123         if (!empty) {
 0124          throw new SharpZipBaseException("!Empty");
 125        }
 0126      }
 127
 128      /// <summary>
 129      /// Set static codes and length
 130      /// </summary>
 131      /// <param name="staticCodes">new codes</param>
 132      /// <param name="staticLengths">length for new codes</param>
 133      public void SetStaticCodes(short[] staticCodes, byte[] staticLengths)
 134      {
 474135        codes = staticCodes;
 474136        length = staticLengths;
 474137      }
 138
 139      /// <summary>
 140      /// Build dynamic codes and lengths
 141      /// </summary>
 142      public void BuildCodes()
 143      {
 3144        int numSymbols = freqs.Length;
 3145        int[] nextCode = new int[maxLength];
 3146        int code = 0;
 147
 3148        codes = new short[freqs.Length];
 149
 150        //        if (DeflaterConstants.DEBUGGING) {
 151        //          //Console.WriteLine("buildCodes: "+freqs.Length);
 152        //        }
 153
 80154         for (int bits = 0; bits < maxLength; bits++) {
 37155          nextCode[bits] = code;
 37156          code += bl_counts[bits] << (15 - bits);
 157
 158          //          if (DeflaterConstants.DEBUGGING) {
 159          //            //Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits]
 160          //                              +" nextCode: "+code);
 161          //          }
 162        }
 163
 164#if DebugDeflation
 165        if ( DeflaterConstants.DEBUGGING && (code != 65536) )
 166        {
 167          throw new SharpZipBaseException("Inconsistent bl_counts!");
 168        }
 169#endif
 576170         for (int i = 0; i < numCodes; i++) {
 285171          int bits = length[i];
 285172           if (bits > 0) {
 173
 174            //            if (DeflaterConstants.DEBUGGING) {
 175            //                //Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+"),
 176            //                                  +bits);
 177            //            }
 178
 38179            codes[i] = BitReverse(nextCode[bits - 1]);
 38180            nextCode[bits - 1] += 1 << (16 - bits);
 181          }
 182        }
 3183      }
 184
 185      public void BuildTree()
 186      {
 1530187        int numSymbols = freqs.Length;
 188
 189        /* heap is a priority queue, sorted by frequency, least frequent
 190        * nodes first.  The heap is a binary tree, with the property, that
 191        * the parent node is smaller than both child nodes.  This assures
 192        * that the smallest node is the first parent.
 193        *
 194        * The binary tree is encoded in an array:  0 is root node and
 195        * the nodes 2*n+1, 2*n+2 are the child nodes of node n.
 196        */
 1530197        int[] heap = new int[numSymbols];
 1530198        int heapLen = 0;
 1530199        int maxCode = 0;
 344760200         for (int n = 0; n < numSymbols; n++) {
 170850201          int freq = freqs[n];
 170850202           if (freq != 0) {
 203            // Insert n into heap
 81797204            int pos = heapLen++;
 205            int ppos;
 161994206             while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq) {
 80197207              heap[pos] = heap[ppos];
 80197208              pos = ppos;
 209            }
 81797210            heap[pos] = n;
 211
 81797212            maxCode = n;
 213          }
 214        }
 215
 216        /* We could encode a single literal with 0 bits but then we
 217        * don't see the literals.  Therefore we force at least two
 218        * literals to avoid this case.  We don't care about order in
 219        * this case, both literals get a 1 bit code.
 220        */
 2077221         while (heapLen < 2) {
 547222           int node = maxCode < 2 ? ++maxCode : 0;
 547223          heap[heapLen++] = node;
 224        }
 225
 1530226        numCodes = Math.Max(maxCode + 1, minNumCodes);
 227
 1530228        int numLeafs = heapLen;
 1530229        int[] childs = new int[4 * heapLen - 2];
 1530230        int[] values = new int[2 * heapLen - 1];
 1530231        int numNodes = numLeafs;
 167748232         for (int i = 0; i < heapLen; i++) {
 82344233          int node = heap[i];
 82344234          childs[2 * i] = node;
 82344235          childs[2 * i + 1] = -1;
 82344236          values[i] = freqs[node] << 8;
 82344237          heap[i] = i;
 238        }
 239
 240        /* Construct the Huffman tree by repeatedly combining the least two
 241        * frequent nodes.
 242        */
 243        do {
 80814244          int first = heap[0];
 80814245          int last = heap[--heapLen];
 246
 247          // Propagate the hole to the leafs of the heap
 80814248          int ppos = 0;
 80814249          int path = 1;
 250
 507013251           while (path < heapLen) {
 426199252             if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]]) {
 191359253              path++;
 254            }
 255
 426199256            heap[ppos] = heap[path];
 426199257            ppos = path;
 426199258            path = path * 2 + 1;
 259          }
 260
 261          /* Now propagate the last element down along path.  Normally
 262          * it shouldn't go too deep.
 263          */
 80814264          int lastVal = values[last];
 103741265           while ((path = ppos) > 0 && values[heap[ppos = (path - 1) / 2]] > lastVal) {
 22927266            heap[path] = heap[ppos];
 267          }
 80814268          heap[path] = last;
 269
 270
 80814271          int second = heap[0];
 272
 273          // Create a new node father of first and second
 80814274          last = numNodes++;
 80814275          childs[2 * last] = first;
 80814276          childs[2 * last + 1] = second;
 80814277          int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff);
 80814278          values[last] = lastVal = values[first] + values[second] - mindepth + 1;
 279
 280          // Again, propagate the hole to the leafs
 80814281          ppos = 0;
 80814282          path = 1;
 283
 507819284           while (path < heapLen) {
 427005285             if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]]) {
 193052286              path++;
 287            }
 288
 427005289            heap[ppos] = heap[path];
 427005290            ppos = path;
 427005291            path = ppos * 2 + 1;
 292          }
 293
 294          // Now propagate the new element down along path
 86039295           while ((path = ppos) > 0 && values[heap[ppos = (path - 1) / 2]] > lastVal) {
 5225296            heap[path] = heap[ppos];
 297          }
 80814298          heap[path] = last;
 80814299         } while (heapLen > 1);
 300
 1530301         if (heap[0] != childs.Length / 2 - 1) {
 0302          throw new SharpZipBaseException("Heap invariant violated");
 303        }
 304
 1530305        BuildLength(childs);
 1530306      }
 307
 308      /// <summary>
 309      /// Get encoded length
 310      /// </summary>
 311      /// <returns>Encoded length, the sum of frequencies * lengths</returns>
 312      public int GetEncodedLength()
 313      {
 1530314        int len = 0;
 344760315         for (int i = 0; i < freqs.Length; i++) {
 170850316          len += freqs[i] * length[i];
 317        }
 1530318        return len;
 319      }
 320
 321      /// <summary>
 322      /// Scan a literal or distance tree to determine the frequencies of the codes
 323      /// in the bit length tree.
 324      /// </summary>
 325      public void CalcBLFreq(Tree blTree)
 326      {
 327        int max_count;               /* max repeat count */
 328        int min_count;               /* min repeat count */
 329        int count;                   /* repeat count of the current code */
 1020330        int curlen = -1;             /* length of current code */
 331
 1020332        int i = 0;
 26206333         while (i < numCodes) {
 25186334          count = 1;
 25186335          int nextlen = length[i];
 25186336           if (nextlen == 0) {
 2966337            max_count = 138;
 2966338            min_count = 3;
 2966339          } else {
 22220340            max_count = 6;
 22220341            min_count = 3;
 22220342             if (curlen != nextlen) {
 12628343              blTree.freqs[nextlen]++;
 12628344              count = 0;
 345            }
 346          }
 25186347          curlen = nextlen;
 25186348          i++;
 349
 129433350           while (i < numCodes && curlen == length[i]) {
 114222351            i++;
 114222352             if (++count >= max_count) {
 353              break;
 354            }
 355          }
 356
 25186357           if (count < min_count) {
 13100358            blTree.freqs[curlen] += (short)count;
 25186359           } else if (curlen != 0) {
 10711360            blTree.freqs[REP_3_6]++;
 12086361           } else if (count <= 10) {
 319362            blTree.freqs[REP_3_10]++;
 319363          } else {
 1056364            blTree.freqs[REP_11_138]++;
 365          }
 366        }
 1020367      }
 368
 369      /// <summary>
 370      /// Write tree values
 371      /// </summary>
 372      /// <param name="blTree">Tree to write</param>
 373      public void WriteTree(Tree blTree)
 374      {
 375        int max_count;               // max repeat count
 376        int min_count;               // min repeat count
 377        int count;                   // repeat count of the current code
 2378        int curlen = -1;             // length of current code
 379
 2380        int i = 0;
 42381         while (i < numCodes) {
 40382          count = 1;
 40383          int nextlen = length[i];
 40384           if (nextlen == 0) {
 14385            max_count = 138;
 14386            min_count = 3;
 14387          } else {
 26388            max_count = 6;
 26389            min_count = 3;
 26390             if (curlen != nextlen) {
 26391              blTree.WriteSymbol(nextlen);
 26392              count = 0;
 393            }
 394          }
 40395          curlen = nextlen;
 40396          i++;
 397
 266398           while (i < numCodes && curlen == length[i]) {
 226399            i++;
 226400             if (++count >= max_count) {
 401              break;
 402            }
 403          }
 404
 40405           if (count < min_count) {
 41406             while (count-- > 0) {
 10407              blTree.WriteSymbol(curlen);
 408            }
 40409           } else if (curlen != 0) {
 0410            blTree.WriteSymbol(REP_3_6);
 0411            dh.pending.WriteBits(count - 3, 2);
 9412           } else if (count <= 10) {
 4413            blTree.WriteSymbol(REP_3_10);
 4414            dh.pending.WriteBits(count - 3, 3);
 4415          } else {
 5416            blTree.WriteSymbol(REP_11_138);
 5417            dh.pending.WriteBits(count - 11, 7);
 418          }
 419        }
 2420      }
 421
 422      void BuildLength(int[] childs)
 423      {
 1530424        this.length = new byte[freqs.Length];
 1530425        int numNodes = childs.Length / 2;
 1530426        int numLeafs = (numNodes + 1) / 2;
 1530427        int overflow = 0;
 428
 40800429         for (int i = 0; i < maxLength; i++) {
 18870430          bl_counts[i] = 0;
 431        }
 432
 433        // First calculate optimal bit lengths
 1530434        int[] lengths = new int[numNodes];
 1530435        lengths[numNodes - 1] = 0;
 436
 329376437         for (int i = numNodes - 1; i >= 0; i--) {
 163158438           if (childs[2 * i + 1] != -1) {
 80814439            int bitLength = lengths[i] + 1;
 80814440             if (bitLength > maxLength) {
 2441              bitLength = maxLength;
 2442              overflow++;
 443            }
 80814444            lengths[childs[2 * i]] = lengths[childs[2 * i + 1]] = bitLength;
 80814445          } else {
 446            // A leaf node
 82344447            int bitLength = lengths[i];
 82344448            bl_counts[bitLength - 1]++;
 82344449            this.length[childs[2 * i]] = (byte)lengths[i];
 450          }
 451        }
 452
 453        //        if (DeflaterConstants.DEBUGGING) {
 454        //          //Console.WriteLine("Tree "+freqs.Length+" lengths:");
 455        //          for (int i=0; i < numLeafs; i++) {
 456        //            //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
 457        //                              + " len: "+length[childs[2*i]]);
 458        //          }
 459        //        }
 460
 1530461         if (overflow == 0) {
 1528462          return;
 463        }
 464
 2465        int incrBitLen = maxLength - 1;
 466        do {
 467          // Find the first bit length which could increase:
 2468           while (bl_counts[--incrBitLen] == 0) {
 469          }
 470
 471          // Move this node one down and remove a corresponding
 472          // number of overflow nodes.
 473          do {
 2474            bl_counts[incrBitLen]--;
 2475            bl_counts[++incrBitLen]++;
 2476            overflow -= 1 << (maxLength - 1 - incrBitLen);
 2477           } while (overflow > 0 && incrBitLen < maxLength - 1);
 2478         } while (overflow > 0);
 479
 480        /* We may have overshot above.  Move some nodes from maxLength to
 481        * maxLength-1 in that case.
 482        */
 2483        bl_counts[maxLength - 1] += overflow;
 2484        bl_counts[maxLength - 2] -= overflow;
 485
 486        /* Now recompute all bit lengths, scanning in increasing
 487        * frequency.  It is simpler to reconstruct all lengths instead of
 488        * fixing only the wrong ones. This idea is taken from 'ar'
 489        * written by Haruhiko Okumura.
 490        *
 491        * The nodes were inserted with decreasing frequency into the childs
 492        * array.
 493        */
 2494        int nodePtr = 2 * numLeafs;
 32495         for (int bits = maxLength; bits != 0; bits--) {
 14496          int n = bl_counts[bits - 1];
 44497           while (n > 0) {
 30498            int childPtr = 2 * childs[nodePtr++];
 30499             if (childs[childPtr + 1] == -1) {
 500              // We found another leaf
 18501              length[childs[childPtr]] = (byte)bits;
 18502              n--;
 503            }
 504          }
 505        }
 506        //        if (DeflaterConstants.DEBUGGING) {
 507        //          //Console.WriteLine("*** After overflow elimination. ***");
 508        //          for (int i=0; i < numLeafs; i++) {
 509        //            //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
 510        //                              + " len: "+length[childs[2*i]]);
 511        //          }
 512        //        }
 2513      }
 514
 515    }
 516
 517    #region Instance Fields
 518    /// <summary>
 519    /// Pending buffer to use
 520    /// </summary>
 521    public DeflaterPending pending;
 522
 523    Tree literalTree;
 524    Tree distTree;
 525    Tree blTree;
 526
 527    // Buffer for distances
 528    short[] d_buf;
 529    byte[] l_buf;
 530    int last_lit;
 531    int extra_bits;
 532    #endregion
 533
 534    static DeflaterHuffman()
 535    {
 536      // See RFC 1951 3.2.6
 537      // Literal codes
 1538      staticLCodes = new short[LITERAL_NUM];
 1539      staticLLength = new byte[LITERAL_NUM];
 540
 1541      int i = 0;
 145542       while (i < 144) {
 144543        staticLCodes[i] = BitReverse((0x030 + i) << 8);
 144544        staticLLength[i++] = 8;
 545      }
 546
 113547       while (i < 256) {
 112548        staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);
 112549        staticLLength[i++] = 9;
 550      }
 551
 25552       while (i < 280) {
 24553        staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);
 24554        staticLLength[i++] = 7;
 555      }
 556
 7557       while (i < LITERAL_NUM) {
 6558        staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8);
 6559        staticLLength[i++] = 8;
 560      }
 561
 562      // Distance codes
 1563      staticDCodes = new short[DIST_NUM];
 1564      staticDLength = new byte[DIST_NUM];
 62565       for (i = 0; i < DIST_NUM; i++) {
 30566        staticDCodes[i] = BitReverse(i << 11);
 30567        staticDLength[i] = 5;
 568      }
 1569    }
 570
 571    /// <summary>
 572    /// Construct instance with pending buffer
 573    /// </summary>
 574    /// <param name="pending">Pending buffer to use</param>
 273575    public DeflaterHuffman(DeflaterPending pending)
 576    {
 273577      this.pending = pending;
 578
 273579      literalTree = new Tree(this, LITERAL_NUM, 257, 15);
 273580      distTree = new Tree(this, DIST_NUM, 1, 15);
 273581      blTree = new Tree(this, BITLEN_NUM, 4, 7);
 582
 273583      d_buf = new short[BUFSIZE];
 273584      l_buf = new byte[BUFSIZE];
 273585    }
 586
 587    /// <summary>
 588    /// Reset internal state
 589    /// </summary>
 590    public void Reset()
 591    {
 923592      last_lit = 0;
 923593      extra_bits = 0;
 923594      literalTree.Reset();
 923595      distTree.Reset();
 923596      blTree.Reset();
 923597    }
 598
 599    /// <summary>
 600    /// Write all trees to pending buffer
 601    /// </summary>
 602    /// <param name="blTreeCodes">The number/rank of treecodes to send.</param>
 603    public void SendAllTrees(int blTreeCodes)
 604    {
 1605      blTree.BuildCodes();
 1606      literalTree.BuildCodes();
 1607      distTree.BuildCodes();
 1608      pending.WriteBits(literalTree.numCodes - 257, 5);
 1609      pending.WriteBits(distTree.numCodes - 1, 5);
 1610      pending.WriteBits(blTreeCodes - 4, 4);
 38611       for (int rank = 0; rank < blTreeCodes; rank++) {
 18612        pending.WriteBits(blTree.length[BL_ORDER[rank]], 3);
 613      }
 1614      literalTree.WriteTree(blTree);
 1615      distTree.WriteTree(blTree);
 616
 617#if DebugDeflation
 618      if (DeflaterConstants.DEBUGGING) {
 619        blTree.CheckEmpty();
 620      }
 621#endif
 1622    }
 623
 624    /// <summary>
 625    /// Compress current buffer writing data to pending buffer
 626    /// </summary>
 627    public void CompressBlock()
 628    {
 16324629       for (int i = 0; i < last_lit; i++) {
 7924630        int litlen = l_buf[i] & 0xff;
 7924631        int dist = d_buf[i];
 7924632         if (dist-- != 0) {
 633          //          if (DeflaterConstants.DEBUGGING) {
 634          //            Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");
 635          //          }
 636
 91637          int lc = Lcode(litlen);
 91638          literalTree.WriteSymbol(lc);
 639
 91640          int bits = (lc - 261) / 4;
 91641           if (bits > 0 && bits <= 5) {
 25642            pending.WriteBits(litlen & ((1 << bits) - 1), bits);
 643          }
 644
 91645          int dc = Dcode(dist);
 91646          distTree.WriteSymbol(dc);
 647
 91648          bits = dc / 2 - 1;
 91649           if (bits > 0) {
 70650            pending.WriteBits(dist & ((1 << bits) - 1), bits);
 651          }
 70652        } else {
 653          //          if (DeflaterConstants.DEBUGGING) {
 654          //            if (litlen > 32 && litlen < 127) {
 655          //              Console.Write("("+(char)litlen+"): ");
 656          //            } else {
 657          //              Console.Write("{"+litlen+"}: ");
 658          //            }
 659          //          }
 7833660          literalTree.WriteSymbol(litlen);
 661        }
 662      }
 663
 664#if DebugDeflation
 665      if (DeflaterConstants.DEBUGGING) {
 666        Console.Write("EOF: ");
 667      }
 668#endif
 238669      literalTree.WriteSymbol(EOF_SYMBOL);
 670
 671#if DebugDeflation
 672      if (DeflaterConstants.DEBUGGING) {
 673        literalTree.CheckEmpty();
 674        distTree.CheckEmpty();
 675      }
 676#endif
 238677    }
 678
 679    /// <summary>
 680    /// Flush block to output with no compression
 681    /// </summary>
 682    /// <param name="stored">Data to write</param>
 683    /// <param name="storedOffset">Index of first byte to write</param>
 684    /// <param name="storedLength">Count of bytes to write</param>
 685    /// <param name="lastBlock">True if this is the last block</param>
 686    public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
 687    {
 688#if DebugDeflation
 689      //      if (DeflaterConstants.DEBUGGING) {
 690      //        //Console.WriteLine("Flushing stored block "+ storedLength);
 691      //      }
 692#endif
 293693       pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
 293694      pending.AlignToByte();
 293695      pending.WriteShort(storedLength);
 293696      pending.WriteShort(~storedLength);
 293697      pending.WriteBlock(stored, storedOffset, storedLength);
 293698      Reset();
 293699    }
 700
 701    /// <summary>
 702    /// Flush block to output with compression
 703    /// </summary>
 704    /// <param name="stored">Data to flush</param>
 705    /// <param name="storedOffset">Index of first byte to flush</param>
 706    /// <param name="storedLength">Count of bytes to flush</param>
 707    /// <param name="lastBlock">True if this is the last block</param>
 708    public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
 709    {
 510710      literalTree.freqs[EOF_SYMBOL]++;
 711
 712      // Build trees
 510713      literalTree.BuildTree();
 510714      distTree.BuildTree();
 715
 716      // Calculate bitlen frequency
 510717      literalTree.CalcBLFreq(blTree);
 510718      distTree.CalcBLFreq(blTree);
 719
 720      // Build bitlen tree
 510721      blTree.BuildTree();
 722
 510723      int blTreeCodes = 4;
 3556724       for (int i = 18; i > blTreeCodes; i--) {
 1268725         if (blTree.length[BL_ORDER[i]] > 0) {
 510726          blTreeCodes = i + 1;
 727        }
 728      }
 510729      int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() +
 510730        literalTree.GetEncodedLength() + distTree.GetEncodedLength() +
 510731        extra_bits;
 732
 510733      int static_len = extra_bits;
 292740734       for (int i = 0; i < LITERAL_NUM; i++) {
 145860735        static_len += literalTree.freqs[i] * staticLLength[i];
 736      }
 31620737       for (int i = 0; i < DIST_NUM; i++) {
 15300738        static_len += distTree.freqs[i] * staticDLength[i];
 739      }
 510740       if (opt_len >= static_len) {
 741        // Force static trees
 270742        opt_len = static_len;
 743      }
 744
 510745       if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3) {
 746        // Store Block
 747
 748        //        if (DeflaterConstants.DEBUGGING) {
 749        //          //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len
 750        //                            + " <= " + static_len);
 751        //        }
 272752        FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
 510753       } else if (opt_len == static_len) {
 754        // Encode with static tree
 237755         pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3);
 237756        literalTree.SetStaticCodes(staticLCodes, staticLLength);
 237757        distTree.SetStaticCodes(staticDCodes, staticDLength);
 237758        CompressBlock();
 237759        Reset();
 237760      } else {
 761        // Encode with dynamic tree
 1762         pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3);
 1763        SendAllTrees(blTreeCodes);
 1764        CompressBlock();
 1765        Reset();
 766      }
 1767    }
 768
 769    /// <summary>
 770    /// Get value indicating if internal buffer is full
 771    /// </summary>
 772    /// <returns>true if buffer is full</returns>
 773    public bool IsFull()
 774    {
 7208362775      return last_lit >= BUFSIZE;
 776    }
 777
 778    /// <summary>
 779    /// Add literal to buffer
 780    /// </summary>
 781    /// <param name="literal">Literal value to add to buffer.</param>
 782    /// <returns>Value indicating internal buffer is full</returns>
 783    public bool TallyLit(int literal)
 784    {
 785      //      if (DeflaterConstants.DEBUGGING) {
 786      //        if (lit > 32 && lit < 127) {
 787      //          //Console.WriteLine("("+(char)lit+")");
 788      //        } else {
 789      //          //Console.WriteLine("{"+lit+"}");
 790      //        }
 791      //      }
 3602142792      d_buf[last_lit] = 0;
 3602142793      l_buf[last_lit++] = (byte)literal;
 3602142794      literalTree.freqs[literal]++;
 3602142795      return IsFull();
 796    }
 797
 798    /// <summary>
 799    /// Add distance code and length to literal and distance trees
 800    /// </summary>
 801    /// <param name="distance">Distance code</param>
 802    /// <param name="length">Length</param>
 803    /// <returns>Value indicating if internal buffer is full</returns>
 804    public bool TallyDist(int distance, int length)
 805    {
 806      //      if (DeflaterConstants.DEBUGGING) {
 807      //        //Console.WriteLine("[" + distance + "," + length + "]");
 808      //      }
 809
 2828810      d_buf[last_lit] = (short)distance;
 2828811      l_buf[last_lit++] = (byte)(length - 3);
 812
 2828813      int lc = Lcode(length - 3);
 2828814      literalTree.freqs[lc]++;
 2828815       if (lc >= 265 && lc < 285) {
 25816        extra_bits += (lc - 261) / 4;
 817      }
 818
 2828819      int dc = Dcode(distance - 1);
 2828820      distTree.freqs[dc]++;
 2828821       if (dc >= 4) {
 2807822        extra_bits += dc / 2 - 1;
 823      }
 2828824      return IsFull();
 825    }
 826
 827
 828    /// <summary>
 829    /// Reverse the bits of a 16 bit value.
 830    /// </summary>
 831    /// <param name="toReverse">Value to reverse bits</param>
 832    /// <returns>Value with bits reversed</returns>
 833    public static short BitReverse(int toReverse)
 834    {
 712835      return (short)(bit4Reverse[toReverse & 0xF] << 12 |
 712836              bit4Reverse[(toReverse >> 4) & 0xF] << 8 |
 712837              bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
 712838              bit4Reverse[toReverse >> 12]);
 839    }
 840
 841    static int Lcode(int length)
 842    {
 2919843       if (length == 255) {
 82844        return 285;
 845      }
 846
 2837847      int code = 257;
 3067848       while (length >= 8) {
 230849        code += 4;
 230850        length >>= 1;
 851      }
 2837852      return code + length;
 853    }
 854
 855    static int Dcode(int distance)
 856    {
 2919857      int code = 0;
 34328858       while (distance >= 4) {
 31409859        code += 2;
 31409860        distance >>= 1;
 861      }
 2919862      return code + distance;
 863    }
 864  }
 865}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DeflaterOutputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterOutputStream.htm new file mode 100644 index 000000000..51246dacc --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterOutputStream.htm @@ -0,0 +1,536 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\DeflaterOutputStream.cs
Covered lines:76
Uncovered lines:28
Coverable lines:104
Total lines:476
Line coverage:73%
Branch coverage:71.4%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)1100100
.ctor(...)571.4355.56
Finish()787.576.92
EncryptBlock(...)1100100
InitializePassword(...)1100100
InitializeAESPassword(...)200
Deflate()588.8988.89
Seek(...)100
SetLength(...)100
ReadByte()100
Read(...)100
BeginRead(...)100
BeginWrite(...)100
Flush()1100100
Close()4100100
GetAuthCodeIfAES()266.6766.67
WriteByte(...)1100100
Write(...)1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\DeflaterOutputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Security.Cryptography;
 4using ICSharpCode.SharpZipLib.Encryption;
 5
 6namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
 7{
 8  /// <summary>
 9  /// A special stream deflating or compressing the bytes that are
 10  /// written to it.  It uses a Deflater to perform actual deflating.<br/>
 11  /// Authors of the original java version : Tom Tromey, Jochen Hoenicke
 12  /// </summary>
 13  public class DeflaterOutputStream : Stream
 14  {
 15    #region Constructors
 16    /// <summary>
 17    /// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
 18    /// </summary>
 19    /// <param name="baseOutputStream">
 20    /// the output stream where deflated output should be written.
 21    /// </param>
 22    public DeflaterOutputStream(Stream baseOutputStream)
 423      : this(baseOutputStream, new Deflater(), 512)
 24    {
 425    }
 26
 27    /// <summary>
 28    /// Creates a new DeflaterOutputStream with the given Deflater and
 29    /// default buffer size.
 30    /// </summary>
 31    /// <param name="baseOutputStream">
 32    /// the output stream where deflated output should be written.
 33    /// </param>
 34    /// <param name="deflater">
 35    /// the underlying deflater.
 36    /// </param>
 37    public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater)
 26038      : this(baseOutputStream, deflater, 512)
 39    {
 26040    }
 41
 42    /// <summary>
 43    /// Creates a new DeflaterOutputStream with the given Deflater and
 44    /// buffer size.
 45    /// </summary>
 46    /// <param name="baseOutputStream">
 47    /// The output stream where deflated output is written.
 48    /// </param>
 49    /// <param name="deflater">
 50    /// The underlying deflater to use
 51    /// </param>
 52    /// <param name="bufferSize">
 53    /// The buffer size in bytes to use when deflating (minimum value 512)
 54    /// </param>
 55    /// <exception cref="ArgumentOutOfRangeException">
 56    /// bufsize is less than or equal to zero.
 57    /// </exception>
 58    /// <exception cref="ArgumentException">
 59    /// baseOutputStream does not support writing
 60    /// </exception>
 61    /// <exception cref="ArgumentNullException">
 62    /// deflater instance is null
 63    /// </exception>
 27364    public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize)
 65    {
 27366       if (baseOutputStream == null) {
 067        throw new ArgumentNullException(nameof(baseOutputStream));
 68      }
 69
 27370       if (baseOutputStream.CanWrite == false) {
 071        throw new ArgumentException("Must support writing", nameof(baseOutputStream));
 72      }
 73
 27374       if (deflater == null) {
 075        throw new ArgumentNullException(nameof(deflater));
 76      }
 77
 27378       if (bufferSize < 512) {
 079        throw new ArgumentOutOfRangeException(nameof(bufferSize));
 80      }
 81
 27382      baseOutputStream_ = baseOutputStream;
 27383      buffer_ = new byte[bufferSize];
 27384      deflater_ = deflater;
 27385    }
 86    #endregion
 87
 88    #region Public API
 89    /// <summary>
 90    /// Finishes the stream by calling finish() on the deflater.
 91    /// </summary>
 92    /// <exception cref="SharpZipBaseException">
 93    /// Not all input is deflated
 94    /// </exception>
 95    public virtual void Finish()
 96    {
 32597      deflater_.Finish();
 157398       while (!deflater_.IsFinished) {
 124899        int len = deflater_.Deflate(buffer_, 0, buffer_.Length);
 1248100         if (len <= 0) {
 101          break;
 102        }
 103
 1248104         if (cryptoTransform_ != null) {
 196105          EncryptBlock(buffer_, 0, len);
 106        }
 107
 1248108        baseOutputStream_.Write(buffer_, 0, len);
 109      }
 110
 325111       if (!deflater_.IsFinished) {
 0112        throw new SharpZipBaseException("Can't deflate all input?");
 113      }
 114
 325115      baseOutputStream_.Flush();
 116
 325117       if (cryptoTransform_ != null) {
 31118         if (cryptoTransform_ is ZipAESTransform) {
 0119          AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode();
 120        }
 31121        cryptoTransform_.Dispose();
 31122        cryptoTransform_ = null;
 123      }
 325124    }
 125
 126    /// <summary>
 127    /// Get/set flag indicating ownership of the underlying stream.
 128    /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
 129    /// </summary>
 130    public bool IsStreamOwner {
 11131      get { return isStreamOwner_; }
 386132      set { isStreamOwner_ = value; }
 133    }
 134
 135    ///  <summary>
 136    /// Allows client to determine if an entry can be patched after its added
 137    /// </summary>
 138    public bool CanPatchEntries {
 139      get {
 141140        return baseOutputStream_.CanSeek;
 141      }
 142    }
 143
 144    #endregion
 145
 146    #region Encryption
 147
 148    string password;
 149
 150    ICryptoTransform cryptoTransform_;
 151
 152    /// <summary>
 153    /// Returns the 10 byte AUTH CODE to be appended immediately following the AES data stream.
 154    /// </summary>
 155    protected byte[] AESAuthCode;
 156
 157    /// <summary>
 158    /// Get/set the password used for encryption.
 159    /// </summary>
 160    /// <remarks>When set to null or if the password is empty no encryption is performed</remarks>
 161    public string Password {
 162      get {
 361163        return password;
 164      }
 165      set {
 69166         if ((value != null) && (value.Length == 0)) {
 0167          password = null;
 0168        } else {
 69169          password = value;
 170        }
 69171      }
 172    }
 173
 174    /// <summary>
 175    /// Encrypt a block of data
 176    /// </summary>
 177    /// <param name="buffer">
 178    /// Data to encrypt.  NOTE the original contents of the buffer are lost
 179    /// </param>
 180    /// <param name="offset">
 181    /// Offset of first byte in buffer to encrypt
 182    /// </param>
 183    /// <param name="length">
 184    /// Number of bytes in buffer to encrypt
 185    /// </param>
 186    protected void EncryptBlock(byte[] buffer, int offset, int length)
 187    {
 2305188      cryptoTransform_.TransformBlock(buffer, 0, length, buffer, 0);
 2305189    }
 190
 191    /// <summary>
 192    /// Initializes encryption keys based on given <paramref name="password"/>.
 193    /// </summary>
 194    /// <param name="password">The password.</param>
 195    protected void InitializePassword(string password)
 196    {
 33197      var pkManaged = new PkzipClassicManaged();
 33198      byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));
 33199      cryptoTransform_ = pkManaged.CreateEncryptor(key, null);
 33200    }
 201
 202    /// <summary>
 203    /// Initializes encryption keys based on given password.
 204    /// </summary>
 205    protected void InitializeAESPassword(ZipEntry entry, string rawPassword,
 206                      out byte[] salt, out byte[] pwdVerifier)
 207    {
 0208      salt = new byte[entry.AESSaltLen];
 209      // Salt needs to be cryptographically random, and unique per file
 0210       if (_aesRnd == null)
 0211        _aesRnd = new RNGCryptoServiceProvider();
 0212      _aesRnd.GetBytes(salt);
 0213      int blockSize = entry.AESKeySize / 8;   // bits to bytes
 214
 0215      cryptoTransform_ = new ZipAESTransform(rawPassword, salt, blockSize, true);
 0216      pwdVerifier = ((ZipAESTransform)cryptoTransform_).PwdVerifier;
 0217    }
 218
 219    #endregion
 220
 221    #region Deflation Support
 222    /// <summary>
 223    /// Deflates everything in the input buffers.  This will call
 224    /// <code>def.deflate()</code> until all bytes from the input buffers
 225    /// are processed.
 226    /// </summary>
 227    protected void Deflate()
 228    {
 11749229       while (!deflater_.IsNeedingInput) {
 11469230        int deflateCount = deflater_.Deflate(buffer_, 0, buffer_.Length);
 231
 11469232         if (deflateCount <= 0) {
 233          break;
 234        }
 7240235         if (cryptoTransform_ != null) {
 1977236          EncryptBlock(buffer_, 0, deflateCount);
 237        }
 238
 7240239        baseOutputStream_.Write(buffer_, 0, deflateCount);
 240      }
 241
 4509242       if (!deflater_.IsNeedingInput) {
 0243        throw new SharpZipBaseException("DeflaterOutputStream can't deflate all input?");
 244      }
 4509245    }
 246    #endregion
 247
 248    #region Stream Overrides
 249    /// <summary>
 250    /// Gets value indicating stream can be read from
 251    /// </summary>
 252    public override bool CanRead {
 253      get {
 0254        return false;
 255      }
 256    }
 257
 258    /// <summary>
 259    /// Gets a value indicating if seeking is supported for this stream
 260    /// This property always returns false
 261    /// </summary>
 262    public override bool CanSeek {
 263      get {
 2264        return false;
 265      }
 266    }
 267
 268    /// <summary>
 269    /// Get value indicating if this stream supports writing
 270    /// </summary>
 271    public override bool CanWrite {
 272      get {
 5273        return baseOutputStream_.CanWrite;
 274      }
 275    }
 276
 277    /// <summary>
 278    /// Get current length of stream
 279    /// </summary>
 280    public override long Length {
 281      get {
 0282        return baseOutputStream_.Length;
 283      }
 284    }
 285
 286    /// <summary>
 287    /// Gets the current position within the stream.
 288    /// </summary>
 289    /// <exception cref="NotSupportedException">Any attempt to set position</exception>
 290    public override long Position {
 291      get {
 0292        return baseOutputStream_.Position;
 293      }
 294      set {
 0295        throw new NotSupportedException("Position property not supported");
 296      }
 297    }
 298
 299    /// <summary>
 300    /// Sets the current position of this stream to the given value. Not supported by this class!
 301    /// </summary>
 302    /// <param name="offset">The offset relative to the <paramref name="origin"/> to seek.</param>
 303    /// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
 304    /// <returns>The new position in the stream.</returns>
 305    /// <exception cref="NotSupportedException">Any access</exception>
 306    public override long Seek(long offset, SeekOrigin origin)
 307    {
 0308      throw new NotSupportedException("DeflaterOutputStream Seek not supported");
 309    }
 310
 311    /// <summary>
 312    /// Sets the length of this stream to the given value. Not supported by this class!
 313    /// </summary>
 314    /// <param name="value">The new stream length.</param>
 315    /// <exception cref="NotSupportedException">Any access</exception>
 316    public override void SetLength(long value)
 317    {
 0318      throw new NotSupportedException("DeflaterOutputStream SetLength not supported");
 319    }
 320
 321    /// <summary>
 322    /// Read a byte from stream advancing position by one
 323    /// </summary>
 324    /// <returns>The byte read cast to an int.  THe value is -1 if at the end of the stream.</returns>
 325    /// <exception cref="NotSupportedException">Any access</exception>
 326    public override int ReadByte()
 327    {
 0328      throw new NotSupportedException("DeflaterOutputStream ReadByte not supported");
 329    }
 330
 331    /// <summary>
 332    /// Read a block of bytes from stream
 333    /// </summary>
 334    /// <param name="buffer">The buffer to store read data in.</param>
 335    /// <param name="offset">The offset to start storing at.</param>
 336    /// <param name="count">The maximum number of bytes to read.</param>
 337    /// <returns>The actual number of bytes read.  Zero if end of stream is detected.</returns>
 338    /// <exception cref="NotSupportedException">Any access</exception>
 339    public override int Read(byte[] buffer, int offset, int count)
 340    {
 0341      throw new NotSupportedException("DeflaterOutputStream Read not supported");
 342    }
 343
 344    /// <summary>
 345    /// Asynchronous reads are not supported a NotSupportedException is always thrown
 346    /// </summary>
 347    /// <param name="buffer">The buffer to read into.</param>
 348    /// <param name="offset">The offset to start storing data at.</param>
 349    /// <param name="count">The number of bytes to read</param>
 350    /// <param name="callback">The async callback to use.</param>
 351    /// <param name="state">The state to use.</param>
 352    /// <returns>Returns an <see cref="IAsyncResult"/></returns>
 353    /// <exception cref="NotSupportedException">Any access</exception>
 354    public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
 355    {
 0356      throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported");
 357    }
 358
 359    /// <summary>
 360    /// Asynchronous writes arent supported, a NotSupportedException is always thrown
 361    /// </summary>
 362    /// <param name="buffer">The buffer to write.</param>
 363    /// <param name="offset">The offset to begin writing at.</param>
 364    /// <param name="count">The number of bytes to write.</param>
 365    /// <param name="callback">The <see cref="AsyncCallback"/> to use.</param>
 366    /// <param name="state">The state object.</param>
 367    /// <returns>Returns an IAsyncResult.</returns>
 368    /// <exception cref="NotSupportedException">Any access</exception>
 369    public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
 370    {
 0371      throw new NotSupportedException("BeginWrite is not supported");
 372    }
 373
 374    /// <summary>
 375    /// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater and then
 376    /// on the underlying stream.  This ensures that all bytes are flushed.
 377    /// </summary>
 378    public override void Flush()
 379    {
 30380      deflater_.Flush();
 30381      Deflate();
 30382      baseOutputStream_.Flush();
 30383    }
 384
 385    /// <summary>
 386    /// Calls <see cref="Finish"/> and closes the underlying
 387    /// stream when <see cref="IsStreamOwner"></see> is true.
 388    /// </summary>
 389    public override void Close()
 390    {
 267391       if (!isClosed_) {
 259392        isClosed_ = true;
 393
 394        try {
 259395          Finish();
 258396           if (cryptoTransform_ != null) {
 1397            GetAuthCodeIfAES();
 1398            cryptoTransform_.Dispose();
 1399            cryptoTransform_ = null;
 400          }
 258401        } finally {
 259402           if (isStreamOwner_) {
 68403            baseOutputStream_.Close();
 404          }
 259405        }
 406      }
 266407    }
 408
 409    private void GetAuthCodeIfAES()
 410    {
 1411       if (cryptoTransform_ is ZipAESTransform) {
 0412        AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode();
 413      }
 1414    }
 415
 416    /// <summary>
 417    /// Writes a single byte to the compressed output stream.
 418    /// </summary>
 419    /// <param name="value">
 420    /// The byte value.
 421    /// </param>
 422    public override void WriteByte(byte value)
 423    {
 24424      byte[] b = new byte[1];
 24425      b[0] = value;
 24426      Write(b, 0, 1);
 22427    }
 428
 429    /// <summary>
 430    /// Writes bytes from an array to the compressed stream.
 431    /// </summary>
 432    /// <param name="buffer">
 433    /// The byte array
 434    /// </param>
 435    /// <param name="offset">
 436    /// The offset into the byte array where to start.
 437    /// </param>
 438    /// <param name="count">
 439    /// The number of bytes to write.
 440    /// </param>
 441    public override void Write(byte[] buffer, int offset, int count)
 442    {
 4479443      deflater_.SetInput(buffer, offset, count);
 4479444      Deflate();
 4479445    }
 446    #endregion
 447
 448    #region Instance Fields
 449    /// <summary>
 450    /// This buffer is used temporarily to retrieve the bytes from the
 451    /// deflater and write them to the underlying output stream.
 452    /// </summary>
 453    byte[] buffer_;
 454
 455    /// <summary>
 456    /// The deflater which is used to deflate the stream.
 457    /// </summary>
 458    protected Deflater deflater_;
 459
 460    /// <summary>
 461    /// Base stream the deflater depends on.
 462    /// </summary>
 463    protected Stream baseOutputStream_;
 464
 465    bool isClosed_;
 466
 273467    bool isStreamOwner_ = true;
 468    #endregion
 469
 470    #region Static Fields
 471
 472    // Static to help ensure that multiple files within a zip will get different random salt
 473    private static RNGCryptoServiceProvider _aesRnd;
 474    #endregion
 475  }
 476}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DeflaterPending.htm b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterPending.htm new file mode 100644 index 000000000..2c5833543 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DeflaterPending.htm @@ -0,0 +1,58 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterPending.cs
Covered lines:2
Uncovered lines:0
Coverable lines:2
Total lines:17
Line coverage:100%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterPending.cs

+ + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1namespace ICSharpCode.SharpZipLib.Zip.Compression
 2{
 3  /// <summary>
 4  /// This class stores the pending output of the Deflater.
 5  ///
 6  /// author of the original java version : Jochen Hoenicke
 7  /// </summary>
 8  public class DeflaterPending : PendingBuffer
 9  {
 10    /// <summary>
 11    /// Construct instance with default buffer size
 12    /// </summary>
 27313    public DeflaterPending() : base(DeflaterConstants.PENDING_BUF_SIZE)
 14    {
 27315    }
 16  }
 17}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DescriptorData.htm b/docs/opencover/ICSharpCode.SharpZipLib_DescriptorData.htm new file mode 100644 index 000000000..46ecdf5be --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DescriptorData.htm @@ -0,0 +1,594 @@ + + + + +ICSharpCode.SharpZipLib.Zip.DescriptorData - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.DescriptorData
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipHelperStream.cs
Covered lines:6
Uncovered lines:0
Coverable lines:6
Total lines:560
Line coverage:100%
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipHelperStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Text;
 4
 5namespace ICSharpCode.SharpZipLib.Zip
 6{
 7  /// <summary>
 8  /// Holds data pertinent to a data descriptor.
 9  /// </summary>
 10  public class DescriptorData
 11  {
 12    /// <summary>
 13    /// Get /set the compressed size of data.
 14    /// </summary>
 15    public long CompressedSize {
 1316      get { return compressedSize; }
 2617      set { compressedSize = value; }
 18    }
 19
 20    /// <summary>
 21    /// Get / set the uncompressed size of data
 22    /// </summary>
 23    public long Size {
 1324      get { return size; }
 2625      set { size = value; }
 26    }
 27
 28    /// <summary>
 29    /// Get /set the crc value.
 30    /// </summary>
 31    public long Crc {
 1332      get { return crc; }
 2633      set { crc = (value & 0xffffffff); }
 34    }
 35
 36    #region Instance Fields
 37    long size;
 38    long compressedSize;
 39    long crc;
 40    #endregion
 41  }
 42
 43  class EntryPatchData
 44  {
 45    public long SizePatchOffset {
 46      get { return sizePatchOffset_; }
 47      set { sizePatchOffset_ = value; }
 48    }
 49
 50    public long CrcPatchOffset {
 51      get { return crcPatchOffset_; }
 52      set { crcPatchOffset_ = value; }
 53    }
 54
 55    #region Instance Fields
 56    long sizePatchOffset_;
 57    long crcPatchOffset_;
 58    #endregion
 59  }
 60
 61  /// <summary>
 62  /// This class assists with writing/reading from Zip files.
 63  /// </summary>
 64  internal class ZipHelperStream : Stream
 65  {
 66    #region Constructors
 67    /// <summary>
 68    /// Initialise an instance of this class.
 69    /// </summary>
 70    /// <param name="name">The name of the file to open.</param>
 71    public ZipHelperStream(string name)
 72    {
 73      stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite);
 74      isOwner_ = true;
 75    }
 76
 77    /// <summary>
 78    /// Initialise a new instance of <see cref="ZipHelperStream"/>.
 79    /// </summary>
 80    /// <param name="stream">The stream to use.</param>
 81    public ZipHelperStream(Stream stream)
 82    {
 83      stream_ = stream;
 84    }
 85    #endregion
 86
 87    /// <summary>
 88    /// Get / set a value indicating wether the the underlying stream is owned or not.
 89    /// </summary>
 90    /// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>
 91    public bool IsStreamOwner {
 92      get { return isOwner_; }
 93      set { isOwner_ = value; }
 94    }
 95
 96    #region Base Stream Methods
 97    public override bool CanRead {
 98      get { return stream_.CanRead; }
 99    }
 100
 101    public override bool CanSeek {
 102      get { return stream_.CanSeek; }
 103    }
 104
 105    public override bool CanTimeout {
 106      get { return stream_.CanTimeout; }
 107    }
 108
 109    public override long Length {
 110      get { return stream_.Length; }
 111    }
 112
 113    public override long Position {
 114      get { return stream_.Position; }
 115      set { stream_.Position = value; }
 116    }
 117
 118    public override bool CanWrite {
 119      get { return stream_.CanWrite; }
 120    }
 121
 122    public override void Flush()
 123    {
 124      stream_.Flush();
 125    }
 126
 127    public override long Seek(long offset, SeekOrigin origin)
 128    {
 129      return stream_.Seek(offset, origin);
 130    }
 131
 132    public override void SetLength(long value)
 133    {
 134      stream_.SetLength(value);
 135    }
 136
 137    public override int Read(byte[] buffer, int offset, int count)
 138    {
 139      return stream_.Read(buffer, offset, count);
 140    }
 141
 142    public override void Write(byte[] buffer, int offset, int count)
 143    {
 144      stream_.Write(buffer, offset, count);
 145    }
 146
 147    /// <summary>
 148    /// Close the stream.
 149    /// </summary>
 150    /// <remarks>
 151    /// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.
 152    /// </remarks>
 153    override public void Close()
 154    {
 155      Stream toClose = stream_;
 156      stream_ = null;
 157      if (isOwner_ && (toClose != null)) {
 158        isOwner_ = false;
 159        toClose.Close();
 160      }
 161    }
 162    #endregion
 163
 164    // Write the local file header
 165    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
 166    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
 167    {
 168      CompressionMethod method = entry.CompressionMethod;
 169      bool headerInfoAvailable = true; // How to get this?
 170      bool patchEntryHeader = false;
 171
 172      WriteLEInt(ZipConstants.LocalHeaderSignature);
 173
 174      WriteLEShort(entry.Version);
 175      WriteLEShort(entry.Flags);
 176      WriteLEShort((byte)method);
 177      WriteLEInt((int)entry.DosTime);
 178
 179      if (headerInfoAvailable == true) {
 180        WriteLEInt((int)entry.Crc);
 181        if (entry.LocalHeaderRequiresZip64) {
 182          WriteLEInt(-1);
 183          WriteLEInt(-1);
 184        } else {
 185          WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.Compressed
 186          WriteLEInt((int)entry.Size);
 187        }
 188      } else {
 189        if (patchData != null) {
 190          patchData.CrcPatchOffset = stream_.Position;
 191        }
 192        WriteLEInt(0);  // Crc
 193
 194        if (patchData != null) {
 195          patchData.SizePatchOffset = stream_.Position;
 196        }
 197
 198        // For local header both sizes appear in Zip64 Extended Information
 199        if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {
 200          WriteLEInt(-1);
 201          WriteLEInt(-1);
 202        } else {
 203          WriteLEInt(0);  // Compressed size
 204          WriteLEInt(0);  // Uncompressed size
 205        }
 206      }
 207
 208      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 209
 210      if (name.Length > 0xFFFF) {
 211        throw new ZipException("Entry name too long.");
 212      }
 213
 214      var ed = new ZipExtraData(entry.ExtraData);
 215
 216      if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) {
 217        ed.StartNewEntry();
 218        if (headerInfoAvailable) {
 219          ed.AddLeLong(entry.Size);
 220          ed.AddLeLong(entry.CompressedSize);
 221        } else {
 222          ed.AddLeLong(-1);
 223          ed.AddLeLong(-1);
 224        }
 225        ed.AddNewEntry(1);
 226
 227        if (!ed.Find(1)) {
 228          throw new ZipException("Internal error cant find extra data");
 229        }
 230
 231        if (patchData != null) {
 232          patchData.SizePatchOffset = ed.CurrentReadIndex;
 233        }
 234      } else {
 235        ed.Delete(1);
 236      }
 237
 238      byte[] extra = ed.GetEntryData();
 239
 240      WriteLEShort(name.Length);
 241      WriteLEShort(extra.Length);
 242
 243      if (name.Length > 0) {
 244        stream_.Write(name, 0, name.Length);
 245      }
 246
 247      if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {
 248        patchData.SizePatchOffset += stream_.Position;
 249      }
 250
 251      if (extra.Length > 0) {
 252        stream_.Write(extra, 0, extra.Length);
 253      }
 254    }
 255
 256    /// <summary>
 257    /// Locates a block with the desired <paramref name="signature"/>.
 258    /// </summary>
 259    /// <param name="signature">The signature to find.</param>
 260    /// <param name="endLocation">Location, marking the end of block.</param>
 261    /// <param name="minimumBlockSize">Minimum size of the block.</param>
 262    /// <param name="maximumVariableData">The maximum variable data.</param>
 263    /// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns>
 264    public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 265    {
 266      long pos = endLocation - minimumBlockSize;
 267      if (pos < 0) {
 268        return -1;
 269      }
 270
 271      long giveUpMarker = Math.Max(pos - maximumVariableData, 0);
 272
 273      // TODO: This loop could be optimised for speed.
 274      do {
 275        if (pos < giveUpMarker) {
 276          return -1;
 277        }
 278        Seek(pos--, SeekOrigin.Begin);
 279      } while (ReadLEInt() != signature);
 280
 281      return Position;
 282    }
 283
 284    /// <summary>
 285    /// Write Zip64 end of central directory records (File header and locator).
 286    /// </summary>
 287    /// <param name="noOfEntries">The number of entries in the central directory.</param>
 288    /// <param name="sizeEntries">The size of entries in the central directory.</param>
 289    /// <param name="centralDirOffset">The offset of the dentral directory.</param>
 290    public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)
 291    {
 292      long centralSignatureOffset = stream_.Position;
 293      WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature);
 294      WriteLELong(44);    // Size of this record (total size of remaining fields in header or full size - 12)
 295      WriteLEShort(ZipConstants.VersionMadeBy);   // Version made by
 296      WriteLEShort(ZipConstants.VersionZip64);   // Version to extract
 297      WriteLEInt(0);      // Number of this disk
 298      WriteLEInt(0);      // number of the disk with the start of the central directory
 299      WriteLELong(noOfEntries);       // No of entries on this disk
 300      WriteLELong(noOfEntries);       // Total No of entries in central directory
 301      WriteLELong(sizeEntries);       // Size of the central directory
 302      WriteLELong(centralDirOffset);  // offset of start of central directory
 303                      // zip64 extensible data sector not catered for here (variable size)
 304
 305      // Write the Zip64 end of central directory locator
 306      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);
 307
 308      // no of the disk with the start of the zip64 end of central directory
 309      WriteLEInt(0);
 310
 311      // relative offset of the zip64 end of central directory record
 312      WriteLELong(centralSignatureOffset);
 313
 314      // total number of disks
 315      WriteLEInt(1);
 316    }
 317
 318    /// <summary>
 319    /// Write the required records to end the central directory.
 320    /// </summary>
 321    /// <param name="noOfEntries">The number of entries in the directory.</param>
 322    /// <param name="sizeEntries">The size of the entries in the directory.</param>
 323    /// <param name="startOfCentralDirectory">The start of the central directory.</param>
 324    /// <param name="comment">The archive comment.  (This can be null).</param>
 325    public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,
 326      long startOfCentralDirectory, byte[] comment)
 327    {
 328
 329      if ((noOfEntries >= 0xffff) ||
 330        (startOfCentralDirectory >= 0xffffffff) ||
 331        (sizeEntries >= 0xffffffff)) {
 332        WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);
 333      }
 334
 335      WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);
 336
 337      // TODO: ZipFile Multi disk handling not done
 338      WriteLEShort(0);                    // number of this disk
 339      WriteLEShort(0);                    // no of disk with start of central dir
 340
 341
 342      // Number of entries
 343      if (noOfEntries >= 0xffff) {
 344        WriteLEUshort(0xffff);  // Zip64 marker
 345        WriteLEUshort(0xffff);
 346      } else {
 347        WriteLEShort((short)noOfEntries);          // entries in central dir for this disk
 348        WriteLEShort((short)noOfEntries);          // total entries in central directory
 349      }
 350
 351      // Size of the central directory
 352      if (sizeEntries >= 0xffffffff) {
 353        WriteLEUint(0xffffffff);    // Zip64 marker
 354      } else {
 355        WriteLEInt((int)sizeEntries);
 356      }
 357
 358
 359      // offset of start of central directory
 360      if (startOfCentralDirectory >= 0xffffffff) {
 361        WriteLEUint(0xffffffff);    // Zip64 marker
 362      } else {
 363        WriteLEInt((int)startOfCentralDirectory);
 364      }
 365
 366      int commentLength = (comment != null) ? comment.Length : 0;
 367
 368      if (commentLength > 0xffff) {
 369        throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));
 370      }
 371
 372      WriteLEShort(commentLength);
 373
 374      if (commentLength > 0) {
 375        Write(comment, 0, comment.Length);
 376      }
 377    }
 378
 379    #region LE value reading/writing
 380    /// <summary>
 381    /// Read an unsigned short in little endian byte order.
 382    /// </summary>
 383    /// <returns>Returns the value read.</returns>
 384    /// <exception cref="IOException">
 385    /// An i/o error occurs.
 386    /// </exception>
 387    /// <exception cref="EndOfStreamException">
 388    /// The file ends prematurely
 389    /// </exception>
 390    public int ReadLEShort()
 391    {
 392      int byteValue1 = stream_.ReadByte();
 393
 394      if (byteValue1 < 0) {
 395        throw new EndOfStreamException();
 396      }
 397
 398      int byteValue2 = stream_.ReadByte();
 399      if (byteValue2 < 0) {
 400        throw new EndOfStreamException();
 401      }
 402
 403      return byteValue1 | (byteValue2 << 8);
 404    }
 405
 406    /// <summary>
 407    /// Read an int in little endian byte order.
 408    /// </summary>
 409    /// <returns>Returns the value read.</returns>
 410    /// <exception cref="IOException">
 411    /// An i/o error occurs.
 412    /// </exception>
 413    /// <exception cref="System.IO.EndOfStreamException">
 414    /// The file ends prematurely
 415    /// </exception>
 416    public int ReadLEInt()
 417    {
 418      return ReadLEShort() | (ReadLEShort() << 16);
 419    }
 420
 421    /// <summary>
 422    /// Read a long in little endian byte order.
 423    /// </summary>
 424    /// <returns>The value read.</returns>
 425    public long ReadLELong()
 426    {
 427      return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);
 428    }
 429
 430    /// <summary>
 431    /// Write an unsigned short in little endian byte order.
 432    /// </summary>
 433    /// <param name="value">The value to write.</param>
 434    public void WriteLEShort(int value)
 435    {
 436      stream_.WriteByte((byte)(value & 0xff));
 437      stream_.WriteByte((byte)((value >> 8) & 0xff));
 438    }
 439
 440    /// <summary>
 441    /// Write a ushort in little endian byte order.
 442    /// </summary>
 443    /// <param name="value">The value to write.</param>
 444    public void WriteLEUshort(ushort value)
 445    {
 446      stream_.WriteByte((byte)(value & 0xff));
 447      stream_.WriteByte((byte)(value >> 8));
 448    }
 449
 450    /// <summary>
 451    /// Write an int in little endian byte order.
 452    /// </summary>
 453    /// <param name="value">The value to write.</param>
 454    public void WriteLEInt(int value)
 455    {
 456      WriteLEShort(value);
 457      WriteLEShort(value >> 16);
 458    }
 459
 460    /// <summary>
 461    /// Write a uint in little endian byte order.
 462    /// </summary>
 463    /// <param name="value">The value to write.</param>
 464    public void WriteLEUint(uint value)
 465    {
 466      WriteLEUshort((ushort)(value & 0xffff));
 467      WriteLEUshort((ushort)(value >> 16));
 468    }
 469
 470    /// <summary>
 471    /// Write a long in little endian byte order.
 472    /// </summary>
 473    /// <param name="value">The value to write.</param>
 474    public void WriteLELong(long value)
 475    {
 476      WriteLEInt((int)value);
 477      WriteLEInt((int)(value >> 32));
 478    }
 479
 480    /// <summary>
 481    /// Write a ulong in little endian byte order.
 482    /// </summary>
 483    /// <param name="value">The value to write.</param>
 484    public void WriteLEUlong(ulong value)
 485    {
 486      WriteLEUint((uint)(value & 0xffffffff));
 487      WriteLEUint((uint)(value >> 32));
 488    }
 489
 490    #endregion
 491
 492    /// <summary>
 493    /// Write a data descriptor.
 494    /// </summary>
 495    /// <param name="entry">The entry to write a descriptor for.</param>
 496    /// <returns>Returns the number of descriptor bytes written.</returns>
 497    public int WriteDataDescriptor(ZipEntry entry)
 498    {
 499      if (entry == null) {
 500        throw new ArgumentNullException(nameof(entry));
 501      }
 502
 503      int result = 0;
 504
 505      // Add data descriptor if flagged as required
 506      if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 507        // The signature is not PKZIP originally but is now described as optional
 508        // in the PKZIP Appnote documenting trhe format.
 509        WriteLEInt(ZipConstants.DataDescriptorSignature);
 510        WriteLEInt(unchecked((int)(entry.Crc)));
 511
 512        result += 8;
 513
 514        if (entry.LocalHeaderRequiresZip64) {
 515          WriteLELong(entry.CompressedSize);
 516          WriteLELong(entry.Size);
 517          result += 16;
 518        } else {
 519          WriteLEInt((int)entry.CompressedSize);
 520          WriteLEInt((int)entry.Size);
 521          result += 8;
 522        }
 523      }
 524
 525      return result;
 526    }
 527
 528    /// <summary>
 529    /// Read data descriptor at the end of compressed data.
 530    /// </summary>
 531    /// <param name="zip64">if set to <c>true</c> [zip64].</param>
 532    /// <param name="data">The data to fill in.</param>
 533    /// <returns>Returns the number of bytes read in the descriptor.</returns>
 534    public void ReadDataDescriptor(bool zip64, DescriptorData data)
 535    {
 536      int intValue = ReadLEInt();
 537
 538      // In theory this may not be a descriptor according to PKZIP appnote.
 539      // In practise its always there.
 540      if (intValue != ZipConstants.DataDescriptorSignature) {
 541        throw new ZipException("Data descriptor signature not found");
 542      }
 543
 544      data.Crc = ReadLEInt();
 545
 546      if (zip64) {
 547        data.CompressedSize = ReadLELong();
 548        data.Size = ReadLELong();
 549      } else {
 550        data.CompressedSize = ReadLEInt();
 551        data.Size = ReadLEInt();
 552      }
 553    }
 554
 555    #region Instance Fields
 556    bool isOwner_;
 557    Stream stream_;
 558    #endregion
 559  }
 560}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DirectoryEventArgs.htm b/docs/opencover/ICSharpCode.SharpZipLib_DirectoryEventArgs.htm new file mode 100644 index 000000000..e90b09ae2 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DirectoryEventArgs.htm @@ -0,0 +1,516 @@ + + + + +ICSharpCode.SharpZipLib.Core.DirectoryEventArgs - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.DirectoryEventArgs
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs
Covered lines:0
Uncovered lines:4
Coverable lines:4
Total lines:475
Line coverage:0%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Core
 4{
 5  #region EventArgs
 6  /// <summary>
 7  /// Event arguments for scanning.
 8  /// </summary>
 9  public class ScanEventArgs : EventArgs
 10  {
 11    #region Constructors
 12    /// <summary>
 13    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 14    /// </summary>
 15    /// <param name="name">The file or directory name.</param>
 16    public ScanEventArgs(string name)
 17    {
 18      name_ = name;
 19    }
 20    #endregion
 21
 22    /// <summary>
 23    /// The file or directory name for this event.
 24    /// </summary>
 25    public string Name {
 26      get { return name_; }
 27    }
 28
 29    /// <summary>
 30    /// Get set a value indicating if scanning should continue or not.
 31    /// </summary>
 32    public bool ContinueRunning {
 33      get { return continueRunning_; }
 34      set { continueRunning_ = value; }
 35    }
 36
 37    #region Instance Fields
 38    string name_;
 39    bool continueRunning_ = true;
 40    #endregion
 41  }
 42
 43  /// <summary>
 44  /// Event arguments during processing of a single file or directory.
 45  /// </summary>
 46  public class ProgressEventArgs : EventArgs
 47  {
 48    #region Constructors
 49    /// <summary>
 50    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 51    /// </summary>
 52    /// <param name="name">The file or directory name if known.</param>
 53    /// <param name="processed">The number of bytes processed so far</param>
 54    /// <param name="target">The total number of bytes to process, 0 if not known</param>
 55    public ProgressEventArgs(string name, long processed, long target)
 56    {
 57      name_ = name;
 58      processed_ = processed;
 59      target_ = target;
 60    }
 61    #endregion
 62
 63    /// <summary>
 64    /// The name for this event if known.
 65    /// </summary>
 66    public string Name {
 67      get { return name_; }
 68    }
 69
 70    /// <summary>
 71    /// Get set a value indicating wether scanning should continue or not.
 72    /// </summary>
 73    public bool ContinueRunning {
 74      get { return continueRunning_; }
 75      set { continueRunning_ = value; }
 76    }
 77
 78    /// <summary>
 79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed
 80    /// </summary>
 81    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>
 82    public float PercentComplete {
 83      get {
 84        float result;
 85        if (target_ <= 0) {
 86          result = 0;
 87        } else {
 88          result = ((float)processed_ / (float)target_) * 100.0f;
 89        }
 90        return result;
 91      }
 92    }
 93
 94    /// <summary>
 95    /// The number of bytes processed so far
 96    /// </summary>
 97    public long Processed {
 98      get { return processed_; }
 99    }
 100
 101    /// <summary>
 102    /// The number of bytes to process.
 103    /// </summary>
 104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>
 105    public long Target {
 106      get { return target_; }
 107    }
 108
 109    #region Instance Fields
 110    string name_;
 111    long processed_;
 112    long target_;
 113    bool continueRunning_ = true;
 114    #endregion
 115  }
 116
 117  /// <summary>
 118  /// Event arguments for directories.
 119  /// </summary>
 120  public class DirectoryEventArgs : ScanEventArgs
 121  {
 122    #region Constructors
 123    /// <summary>
 124    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.
 125    /// </summary>
 126    /// <param name="name">The name for this directory.</param>
 127    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par
 128    public DirectoryEventArgs(string name, bool hasMatchingFiles)
 0129      : base(name)
 130    {
 0131      hasMatchingFiles_ = hasMatchingFiles;
 0132    }
 133    #endregion
 134
 135    /// <summary>
 136    /// Get a value indicating if the directory contains any matching files or not.
 137    /// </summary>
 138    public bool HasMatchingFiles {
 0139      get { return hasMatchingFiles_; }
 140    }
 141
 142    readonly
 143
 144    #region Instance Fields
 145    bool hasMatchingFiles_;
 146    #endregion
 147  }
 148
 149  /// <summary>
 150  /// Arguments passed when scan failures are detected.
 151  /// </summary>
 152  public class ScanFailureEventArgs : EventArgs
 153  {
 154    #region Constructors
 155    /// <summary>
 156    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>
 157    /// </summary>
 158    /// <param name="name">The name to apply.</param>
 159    /// <param name="e">The exception to use.</param>
 160    public ScanFailureEventArgs(string name, Exception e)
 161    {
 162      name_ = name;
 163      exception_ = e;
 164      continueRunning_ = true;
 165    }
 166    #endregion
 167
 168    /// <summary>
 169    /// The applicable name.
 170    /// </summary>
 171    public string Name {
 172      get { return name_; }
 173    }
 174
 175    /// <summary>
 176    /// The applicable exception.
 177    /// </summary>
 178    public Exception Exception {
 179      get { return exception_; }
 180    }
 181
 182    /// <summary>
 183    /// Get / set a value indicating wether scanning should continue.
 184    /// </summary>
 185    public bool ContinueRunning {
 186      get { return continueRunning_; }
 187      set { continueRunning_ = value; }
 188    }
 189
 190    #region Instance Fields
 191    string name_;
 192    Exception exception_;
 193    bool continueRunning_;
 194    #endregion
 195  }
 196
 197  #endregion
 198
 199  #region Delegates
 200  /// <summary>
 201  /// Delegate invoked before starting to process a file.
 202  /// </summary>
 203  /// <param name="sender">The source of the event</param>
 204  /// <param name="e">The event arguments.</param>
 205  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);
 206
 207  /// <summary>
 208  /// Delegate invoked during processing of a file or directory
 209  /// </summary>
 210  /// <param name="sender">The source of the event</param>
 211  /// <param name="e">The event arguments.</param>
 212  public delegate void ProgressHandler(object sender, ProgressEventArgs e);
 213
 214  /// <summary>
 215  /// Delegate invoked when a file has been completely processed.
 216  /// </summary>
 217  /// <param name="sender">The source of the event</param>
 218  /// <param name="e">The event arguments.</param>
 219  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);
 220
 221  /// <summary>
 222  /// Delegate invoked when a directory failure is detected.
 223  /// </summary>
 224  /// <param name="sender">The source of the event</param>
 225  /// <param name="e">The event arguments.</param>
 226  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);
 227
 228  /// <summary>
 229  /// Delegate invoked when a file failure is detected.
 230  /// </summary>
 231  /// <param name="sender">The source of the event</param>
 232  /// <param name="e">The event arguments.</param>
 233  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);
 234  #endregion
 235
 236  /// <summary>
 237  /// FileSystemScanner provides facilities scanning of files and directories.
 238  /// </summary>
 239  public class FileSystemScanner
 240  {
 241    #region Constructors
 242    /// <summary>
 243    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 244    /// </summary>
 245    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>
 246    public FileSystemScanner(string filter)
 247    {
 248      fileFilter_ = new PathFilter(filter);
 249    }
 250
 251    /// <summary>
 252    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 253    /// </summary>
 254    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
 255    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>
 256    public FileSystemScanner(string fileFilter, string directoryFilter)
 257    {
 258      fileFilter_ = new PathFilter(fileFilter);
 259      directoryFilter_ = new PathFilter(directoryFilter);
 260    }
 261
 262    /// <summary>
 263    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 264    /// </summary>
 265    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
 266    public FileSystemScanner(IScanFilter fileFilter)
 267    {
 268      fileFilter_ = fileFilter;
 269    }
 270
 271    /// <summary>
 272    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 273    /// </summary>
 274    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>
 275    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>
 276    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)
 277    {
 278      fileFilter_ = fileFilter;
 279      directoryFilter_ = directoryFilter;
 280    }
 281    #endregion
 282
 283    #region Delegates
 284    /// <summary>
 285    /// Delegate to invoke when a directory is processed.
 286    /// </summary>
 287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;
 288
 289    /// <summary>
 290    /// Delegate to invoke when a file is processed.
 291    /// </summary>
 292    public ProcessFileHandler ProcessFile;
 293
 294    /// <summary>
 295    /// Delegate to invoke when processing for a file has finished.
 296    /// </summary>
 297    public CompletedFileHandler CompletedFile;
 298
 299    /// <summary>
 300    /// Delegate to invoke when a directory failure is detected.
 301    /// </summary>
 302    public DirectoryFailureHandler DirectoryFailure;
 303
 304    /// <summary>
 305    /// Delegate to invoke when a file failure is detected.
 306    /// </summary>
 307    public FileFailureHandler FileFailure;
 308    #endregion
 309
 310    /// <summary>
 311    /// Raise the DirectoryFailure event.
 312    /// </summary>
 313    /// <param name="directory">The directory name.</param>
 314    /// <param name="e">The exception detected.</param>
 315    bool OnDirectoryFailure(string directory, Exception e)
 316    {
 317      DirectoryFailureHandler handler = DirectoryFailure;
 318      bool result = (handler != null);
 319      if (result) {
 320        var args = new ScanFailureEventArgs(directory, e);
 321        handler(this, args);
 322        alive_ = args.ContinueRunning;
 323      }
 324      return result;
 325    }
 326
 327    /// <summary>
 328    /// Raise the FileFailure event.
 329    /// </summary>
 330    /// <param name="file">The file name.</param>
 331    /// <param name="e">The exception detected.</param>
 332    bool OnFileFailure(string file, Exception e)
 333    {
 334      FileFailureHandler handler = FileFailure;
 335
 336      bool result = (handler != null);
 337
 338      if (result) {
 339        var args = new ScanFailureEventArgs(file, e);
 340        FileFailure(this, args);
 341        alive_ = args.ContinueRunning;
 342      }
 343      return result;
 344    }
 345
 346    /// <summary>
 347    /// Raise the ProcessFile event.
 348    /// </summary>
 349    /// <param name="file">The file name.</param>
 350    void OnProcessFile(string file)
 351    {
 352      ProcessFileHandler handler = ProcessFile;
 353
 354      if (handler != null) {
 355        var args = new ScanEventArgs(file);
 356        handler(this, args);
 357        alive_ = args.ContinueRunning;
 358      }
 359    }
 360
 361    /// <summary>
 362    /// Raise the complete file event
 363    /// </summary>
 364    /// <param name="file">The file name</param>
 365    void OnCompleteFile(string file)
 366    {
 367      CompletedFileHandler handler = CompletedFile;
 368
 369      if (handler != null) {
 370        var args = new ScanEventArgs(file);
 371        handler(this, args);
 372        alive_ = args.ContinueRunning;
 373      }
 374    }
 375
 376    /// <summary>
 377    /// Raise the ProcessDirectory event.
 378    /// </summary>
 379    /// <param name="directory">The directory name.</param>
 380    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>
 381    void OnProcessDirectory(string directory, bool hasMatchingFiles)
 382    {
 383      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;
 384
 385      if (handler != null) {
 386        var args = new DirectoryEventArgs(directory, hasMatchingFiles);
 387        handler(this, args);
 388        alive_ = args.ContinueRunning;
 389      }
 390    }
 391
 392    /// <summary>
 393    /// Scan a directory.
 394    /// </summary>
 395    /// <param name="directory">The base directory to scan.</param>
 396    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>
 397    public void Scan(string directory, bool recurse)
 398    {
 399      alive_ = true;
 400      ScanDir(directory, recurse);
 401    }
 402
 403    void ScanDir(string directory, bool recurse)
 404    {
 405
 406      try {
 407        string[] names = System.IO.Directory.GetFiles(directory);
 408        bool hasMatch = false;
 409        for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {
 410          if (!fileFilter_.IsMatch(names[fileIndex])) {
 411            names[fileIndex] = null;
 412          } else {
 413            hasMatch = true;
 414          }
 415        }
 416
 417        OnProcessDirectory(directory, hasMatch);
 418
 419        if (alive_ && hasMatch) {
 420          foreach (string fileName in names) {
 421            try {
 422              if (fileName != null) {
 423                OnProcessFile(fileName);
 424                if (!alive_) {
 425                  break;
 426                }
 427              }
 428            } catch (Exception e) {
 429              if (!OnFileFailure(fileName, e)) {
 430                throw;
 431              }
 432            }
 433          }
 434        }
 435      } catch (Exception e) {
 436        if (!OnDirectoryFailure(directory, e)) {
 437          throw;
 438        }
 439      }
 440
 441      if (alive_ && recurse) {
 442        try {
 443          string[] names = System.IO.Directory.GetDirectories(directory);
 444          foreach (string fulldir in names) {
 445            if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {
 446              ScanDir(fulldir, true);
 447              if (!alive_) {
 448                break;
 449              }
 450            }
 451          }
 452        } catch (Exception e) {
 453          if (!OnDirectoryFailure(directory, e)) {
 454            throw;
 455          }
 456        }
 457      }
 458    }
 459
 460    #region Instance Fields
 461    /// <summary>
 462    /// The file filter currently in use.
 463    /// </summary>
 464    IScanFilter fileFilter_;
 465    /// <summary>
 466    /// The directory filter currently in use.
 467    /// </summary>
 468    IScanFilter directoryFilter_;
 469    /// <summary>
 470    /// Flag indicating if scanning should continue running.
 471    /// </summary>
 472    bool alive_;
 473    #endregion
 474  }
 475}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DirectoryFailureHandler.htm b/docs/opencover/ICSharpCode.SharpZipLib_DirectoryFailureHandler.htm new file mode 100644 index 000000000..1e6026acd --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DirectoryFailureHandler.htm @@ -0,0 +1,29 @@ + + + + +ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler
Assembly:ICSharpCode.SharpZipLib
File(s):
Covered lines:0
Uncovered lines:0
Coverable lines:0
Total lines:0
Line coverage:
+

File(s)

+

No files found. This usually happens if a file isn't covered by a test or the class does not contain any sequence points (e.g. a class that only contains auto properties).

+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DiskArchiveStorage.htm b/docs/opencover/ICSharpCode.SharpZipLib_DiskArchiveStorage.htm new file mode 100644 index 000000000..85960e1f1 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DiskArchiveStorage.htm @@ -0,0 +1,4312 @@ + + + + +ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs
Covered lines:55
Uncovered lines:15
Coverable lines:70
Total lines:4263
Line coverage:78.5%
Branch coverage:62.5%
+

Metrics

+ + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)28066.67
.ctor(...)1100100
GetTemporaryOutput()257.1466.67
ConvertTemporaryToFinal()363.1640
MakeTemporaryCopy(...)1100100
OpenForDirectUpdate(...)485.7157.14
Dispose()2100100
GetTempFileName(...)67588.89
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.IO;
 4using System.Text;
 5using System.Globalization;
 6using System.Security.Cryptography;
 7using ICSharpCode.SharpZipLib.Encryption;
 8using ICSharpCode.SharpZipLib.Core;
 9using ICSharpCode.SharpZipLib.Checksum;
 10using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 11using ICSharpCode.SharpZipLib.Zip.Compression;
 12
 13namespace ICSharpCode.SharpZipLib.Zip
 14{
 15  #region Keys Required Event Args
 16  /// <summary>
 17  /// Arguments used with KeysRequiredEvent
 18  /// </summary>
 19  public class KeysRequiredEventArgs : EventArgs
 20  {
 21    #region Constructors
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 24    /// </summary>
 25    /// <param name="name">The name of the file for which keys are required.</param>
 26    public KeysRequiredEventArgs(string name)
 27    {
 28      fileName = name;
 29    }
 30
 31    /// <summary>
 32    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 33    /// </summary>
 34    /// <param name="name">The name of the file for which keys are required.</param>
 35    /// <param name="keyValue">The current key value.</param>
 36    public KeysRequiredEventArgs(string name, byte[] keyValue)
 37    {
 38      fileName = name;
 39      key = keyValue;
 40    }
 41
 42    #endregion
 43    #region Properties
 44    /// <summary>
 45    /// Gets the name of the file for which keys are required.
 46    /// </summary>
 47    public string FileName {
 48      get { return fileName; }
 49    }
 50
 51    /// <summary>
 52    /// Gets or sets the key value
 53    /// </summary>
 54    public byte[] Key {
 55      get { return key; }
 56      set { key = value; }
 57    }
 58    #endregion
 59
 60    #region Instance Fields
 61    string fileName;
 62    byte[] key;
 63    #endregion
 64  }
 65  #endregion
 66
 67  #region Test Definitions
 68  /// <summary>
 69  /// The strategy to apply to testing.
 70  /// </summary>
 71  public enum TestStrategy
 72  {
 73    /// <summary>
 74    /// Find the first error only.
 75    /// </summary>
 76    FindFirstError,
 77    /// <summary>
 78    /// Find all possible errors.
 79    /// </summary>
 80    FindAllErrors,
 81  }
 82
 83  /// <summary>
 84  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.
 85  /// </summary>
 86  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 87  public enum TestOperation
 88  {
 89    /// <summary>
 90    /// Setting up testing.
 91    /// </summary>
 92    Initialising,
 93
 94    /// <summary>
 95    /// Testing an individual entries header
 96    /// </summary>
 97    EntryHeader,
 98
 99    /// <summary>
 100    /// Testing an individual entries data
 101    /// </summary>
 102    EntryData,
 103
 104    /// <summary>
 105    /// Testing an individual entry has completed.
 106    /// </summary>
 107    EntryComplete,
 108
 109    /// <summary>
 110    /// Running miscellaneous tests
 111    /// </summary>
 112    MiscellaneousTests,
 113
 114    /// <summary>
 115    /// Testing is complete
 116    /// </summary>
 117    Complete,
 118  }
 119
 120  /// <summary>
 121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.
 122  /// </summary>
 123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 124  public class TestStatus
 125  {
 126    #region Constructors
 127    /// <summary>
 128    /// Initialise a new instance of <see cref="TestStatus"/>
 129    /// </summary>
 130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>
 131    public TestStatus(ZipFile file)
 132    {
 133      file_ = file;
 134    }
 135    #endregion
 136
 137    #region Properties
 138
 139    /// <summary>
 140    /// Get the current <see cref="TestOperation"/> in progress.
 141    /// </summary>
 142    public TestOperation Operation {
 143      get { return operation_; }
 144    }
 145
 146    /// <summary>
 147    /// Get the <see cref="ZipFile"/> this status is applicable to.
 148    /// </summary>
 149    public ZipFile File {
 150      get { return file_; }
 151    }
 152
 153    /// <summary>
 154    /// Get the current/last entry tested.
 155    /// </summary>
 156    public ZipEntry Entry {
 157      get { return entry_; }
 158    }
 159
 160    /// <summary>
 161    /// Get the number of errors detected so far.
 162    /// </summary>
 163    public int ErrorCount {
 164      get { return errorCount_; }
 165    }
 166
 167    /// <summary>
 168    /// Get the number of bytes tested so far for the current entry.
 169    /// </summary>
 170    public long BytesTested {
 171      get { return bytesTested_; }
 172    }
 173
 174    /// <summary>
 175    /// Get a value indicating wether the last entry test was valid.
 176    /// </summary>
 177    public bool EntryValid {
 178      get { return entryValid_; }
 179    }
 180    #endregion
 181
 182    #region Internal API
 183    internal void AddError()
 184    {
 185      errorCount_++;
 186      entryValid_ = false;
 187    }
 188
 189    internal void SetOperation(TestOperation operation)
 190    {
 191      operation_ = operation;
 192    }
 193
 194    internal void SetEntry(ZipEntry entry)
 195    {
 196      entry_ = entry;
 197      entryValid_ = true;
 198      bytesTested_ = 0;
 199    }
 200
 201    internal void SetBytesTested(long value)
 202    {
 203      bytesTested_ = value;
 204    }
 205    #endregion
 206
 207    #region Instance Fields
 208    ZipFile file_;
 209    ZipEntry entry_;
 210    bool entryValid_;
 211    int errorCount_;
 212    long bytesTested_;
 213    TestOperation operation_;
 214    #endregion
 215  }
 216
 217  /// <summary>
 218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if
 219  /// </summary>
 220  /// <remarks>If the message is non-null an error has occured.  If the message is null
 221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>
 222  public delegate void ZipTestResultHandler(TestStatus status, string message);
 223  #endregion
 224
 225  #region Update Definitions
 226  /// <summary>
 227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.
 228  /// </summary>
 229  public enum FileUpdateMode
 230  {
 231    /// <summary>
 232    /// Perform all updates on temporary files ensuring that the original file is saved.
 233    /// </summary>
 234    Safe,
 235    /// <summary>
 236    /// Update the archive directly, which is faster but less safe.
 237    /// </summary>
 238    Direct,
 239  }
 240  #endregion
 241
 242  #region ZipFile Class
 243  /// <summary>
 244  /// This class represents a Zip archive.  You can ask for the contained
 245  /// entries, or get an input stream for a file entry.  The entry is
 246  /// automatically decompressed.
 247  ///
 248  /// You can also update the archive adding or deleting entries.
 249  ///
 250  /// This class is thread safe for input:  You can open input streams for arbitrary
 251  /// entries in different threads.
 252  /// <br/>
 253  /// <br/>Author of the original java version : Jochen Hoenicke
 254  /// </summary>
 255  /// <example>
 256  /// <code>
 257  /// using System;
 258  /// using System.Text;
 259  /// using System.Collections;
 260  /// using System.IO;
 261  ///
 262  /// using ICSharpCode.SharpZipLib.Zip;
 263  ///
 264  /// class MainClass
 265  /// {
 266  ///   static public void Main(string[] args)
 267  ///   {
 268  ///     using (ZipFile zFile = new ZipFile(args[0])) {
 269  ///       Console.WriteLine("Listing of : " + zFile.Name);
 270  ///       Console.WriteLine("");
 271  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");
 272  ///       Console.WriteLine("--------  --------  --------  ------  ---------");
 273  ///       foreach (ZipEntry e in zFile) {
 274  ///         if ( e.IsFile ) {
 275  ///           DateTime d = e.DateTime;
 276  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,
 277  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),
 278  ///             e.Name);
 279  ///         }
 280  ///       }
 281  ///     }
 282  ///   }
 283  /// }
 284  /// </code>
 285  /// </example>
 286  public class ZipFile : IEnumerable, IDisposable
 287  {
 288    #region KeyHandling
 289
 290    /// <summary>
 291    /// Delegate for handling keys/password setting during compresion/decompression.
 292    /// </summary>
 293    public delegate void KeysRequiredEventHandler(
 294      object sender,
 295      KeysRequiredEventArgs e
 296    );
 297
 298    /// <summary>
 299    /// Event handler for handling encryption keys.
 300    /// </summary>
 301    public KeysRequiredEventHandler KeysRequired;
 302
 303    /// <summary>
 304    /// Handles getting of encryption keys when required.
 305    /// </summary>
 306    /// <param name="fileName">The file for which encryption keys are required.</param>
 307    void OnKeysRequired(string fileName)
 308    {
 309      if (KeysRequired != null) {
 310        var krea = new KeysRequiredEventArgs(fileName, key);
 311        KeysRequired(this, krea);
 312        key = krea.Key;
 313      }
 314    }
 315
 316    /// <summary>
 317    /// Get/set the encryption key value.
 318    /// </summary>
 319    byte[] Key {
 320      get { return key; }
 321      set { key = value; }
 322    }
 323
 324    /// <summary>
 325    /// Password to be used for encrypting/decrypting files.
 326    /// </summary>
 327    /// <remarks>Set to null if no password is required.</remarks>
 328    public string Password {
 329      set {
 330        if (string.IsNullOrEmpty(value)) {
 331          key = null;
 332        } else {
 333          rawPassword_ = value;
 334          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));
 335        }
 336      }
 337    }
 338
 339    /// <summary>
 340    /// Get a value indicating wether encryption keys are currently available.
 341    /// </summary>
 342    bool HaveKeys {
 343      get { return key != null; }
 344    }
 345    #endregion
 346
 347    #region Constructors
 348    /// <summary>
 349    /// Opens a Zip file with the given name for reading.
 350    /// </summary>
 351    /// <param name="name">The name of the file to open.</param>
 352    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>
 353    /// <exception cref="IOException">
 354    /// An i/o error occurs
 355    /// </exception>
 356    /// <exception cref="ZipException">
 357    /// The file doesn't contain a valid zip archive.
 358    /// </exception>
 359    public ZipFile(string name)
 360    {
 361      if (name == null) {
 362        throw new ArgumentNullException(nameof(name));
 363      }
 364
 365      name_ = name;
 366
 367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 368      isStreamOwner = true;
 369
 370      try {
 371        ReadEntries();
 372      } catch {
 373        DisposeInternal(true);
 374        throw;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Opens a Zip file reading the given <see cref="FileStream"/>.
 380    /// </summary>
 381    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>
 382    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>
 383    /// <exception cref="IOException">
 384    /// An i/o error occurs.
 385    /// </exception>
 386    /// <exception cref="ZipException">
 387    /// The file doesn't contain a valid zip archive.
 388    /// </exception>
 389    public ZipFile(FileStream file)
 390    {
 391      if (file == null) {
 392        throw new ArgumentNullException(nameof(file));
 393      }
 394
 395      if (!file.CanSeek) {
 396        throw new ArgumentException("Stream is not seekable", nameof(file));
 397      }
 398
 399      baseStream_ = file;
 400      name_ = file.Name;
 401      isStreamOwner = true;
 402
 403      try {
 404        ReadEntries();
 405      } catch {
 406        DisposeInternal(true);
 407        throw;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Opens a Zip file reading the given <see cref="Stream"/>.
 413    /// </summary>
 414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
 415    /// <exception cref="IOException">
 416    /// An i/o error occurs
 417    /// </exception>
 418    /// <exception cref="ZipException">
 419    /// The stream doesn't contain a valid zip archive.<br/>
 420    /// </exception>
 421    /// <exception cref="ArgumentException">
 422    /// The <see cref="Stream">stream</see> doesnt support seeking.
 423    /// </exception>
 424    /// <exception cref="ArgumentNullException">
 425    /// The <see cref="Stream">stream</see> argument is null.
 426    /// </exception>
 427    public ZipFile(Stream stream)
 428    {
 429      if (stream == null) {
 430        throw new ArgumentNullException(nameof(stream));
 431      }
 432
 433      if (!stream.CanSeek) {
 434        throw new ArgumentException("Stream is not seekable", nameof(stream));
 435      }
 436
 437      baseStream_ = stream;
 438      isStreamOwner = true;
 439
 440      if (baseStream_.Length > 0) {
 441        try {
 442          ReadEntries();
 443        } catch {
 444          DisposeInternal(true);
 445          throw;
 446        }
 447      } else {
 448        entries_ = new ZipEntry[0];
 449        isNewArchive_ = true;
 450      }
 451    }
 452
 453    /// <summary>
 454    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
 455    /// </summary>
 456    internal ZipFile()
 457    {
 458      entries_ = new ZipEntry[0];
 459      isNewArchive_ = true;
 460    }
 461
 462    #endregion
 463
 464    #region Destructors and Closing
 465    /// <summary>
 466    /// Finalize this instance.
 467    /// </summary>
 468    ~ZipFile()
 469    {
 470      Dispose(false);
 471    }
 472
 473    /// <summary>
 474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying
 475    /// Once closed, no further instance methods should be called.
 476    /// </summary>
 477    /// <exception cref="System.IO.IOException">
 478    /// An i/o error occurs.
 479    /// </exception>
 480    public void Close()
 481    {
 482      DisposeInternal(true);
 483      GC.SuppressFinalize(this);
 484    }
 485
 486    #endregion
 487
 488    #region Creators
 489    /// <summary>
 490    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.
 491    /// </summary>
 492    /// <param name="fileName">The name of the archive to create.</param>
 493    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 494    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>
 495    public static ZipFile Create(string fileName)
 496    {
 497      if (fileName == null) {
 498        throw new ArgumentNullException(nameof(fileName));
 499      }
 500
 501      FileStream fs = File.Create(fileName);
 502
 503      var result = new ZipFile();
 504      result.name_ = fileName;
 505      result.baseStream_ = fs;
 506      result.isStreamOwner = true;
 507      return result;
 508    }
 509
 510    /// <summary>
 511    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.
 512    /// </summary>
 513    /// <param name="outStream">The stream providing data storage.</param>
 514    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 515    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>
 516    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>
 517    public static ZipFile Create(Stream outStream)
 518    {
 519      if (outStream == null) {
 520        throw new ArgumentNullException(nameof(outStream));
 521      }
 522
 523      if (!outStream.CanWrite) {
 524        throw new ArgumentException("Stream is not writeable", nameof(outStream));
 525      }
 526
 527      if (!outStream.CanSeek) {
 528        throw new ArgumentException("Stream is not seekable", nameof(outStream));
 529      }
 530
 531      var result = new ZipFile();
 532      result.baseStream_ = outStream;
 533      return result;
 534    }
 535
 536    #endregion
 537
 538    #region Properties
 539    /// <summary>
 540    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
 541    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
 542    /// </summary>
 543    /// <remarks>
 544    /// The default value is true in all cases.
 545    /// </remarks>
 546    public bool IsStreamOwner {
 547      get { return isStreamOwner; }
 548      set { isStreamOwner = value; }
 549    }
 550
 551    /// <summary>
 552    /// Get a value indicating wether
 553    /// this archive is embedded in another file or not.
 554    /// </summary>
 555    public bool IsEmbeddedArchive {
 556      // Not strictly correct in all circumstances currently
 557      get { return offsetOfFirstEntry > 0; }
 558    }
 559
 560    /// <summary>
 561    /// Get a value indicating that this archive is a new one.
 562    /// </summary>
 563    public bool IsNewArchive {
 564      get { return isNewArchive_; }
 565    }
 566
 567    /// <summary>
 568    /// Gets the comment for the zip file.
 569    /// </summary>
 570    public string ZipFileComment {
 571      get { return comment_; }
 572    }
 573
 574    /// <summary>
 575    /// Gets the name of this zip file.
 576    /// </summary>
 577    public string Name {
 578      get { return name_; }
 579    }
 580
 581    /// <summary>
 582    /// Gets the number of entries in this zip file.
 583    /// </summary>
 584    /// <exception cref="InvalidOperationException">
 585    /// The Zip file has been closed.
 586    /// </exception>
 587    [Obsolete("Use the Count property instead")]
 588    public int Size {
 589      get {
 590        return entries_.Length;
 591      }
 592    }
 593
 594    /// <summary>
 595    /// Get the number of entries contained in this <see cref="ZipFile"/>.
 596    /// </summary>
 597    public long Count {
 598      get {
 599        return entries_.Length;
 600      }
 601    }
 602
 603    /// <summary>
 604    /// Indexer property for ZipEntries
 605    /// </summary>
 606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
 607    public ZipEntry this[int index] {
 608      get {
 609        return (ZipEntry)entries_[index].Clone();
 610      }
 611    }
 612
 613    #endregion
 614
 615    #region Input Handling
 616    /// <summary>
 617    /// Gets an enumerator for the Zip entries in this Zip file.
 618    /// </summary>
 619    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>
 620    /// <exception cref="ObjectDisposedException">
 621    /// The Zip file has been closed.
 622    /// </exception>
 623    public IEnumerator GetEnumerator()
 624    {
 625      if (isDisposed_) {
 626        throw new ObjectDisposedException("ZipFile");
 627      }
 628
 629      return new ZipEntryEnumerator(entries_);
 630    }
 631
 632    /// <summary>
 633    /// Return the index of the entry with a matching name
 634    /// </summary>
 635    /// <param name="name">Entry name to find</param>
 636    /// <param name="ignoreCase">If true the comparison is case insensitive</param>
 637    /// <returns>The index position of the matching entry or -1 if not found</returns>
 638    /// <exception cref="ObjectDisposedException">
 639    /// The Zip file has been closed.
 640    /// </exception>
 641    public int FindEntry(string name, bool ignoreCase)
 642    {
 643      if (isDisposed_) {
 644        throw new ObjectDisposedException("ZipFile");
 645      }
 646
 647      // TODO: This will be slow as the next ice age for huge archives!
 648      for (int i = 0; i < entries_.Length; i++) {
 649        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {
 650          return i;
 651        }
 652      }
 653      return -1;
 654    }
 655
 656    /// <summary>
 657    /// Searches for a zip entry in this archive with the given name.
 658    /// String comparisons are case insensitive
 659    /// </summary>
 660    /// <param name="name">
 661    /// The name to find. May contain directory components separated by slashes ('/').
 662    /// </param>
 663    /// <returns>
 664    /// A clone of the zip entry, or null if no entry with that name exists.
 665    /// </returns>
 666    /// <exception cref="ObjectDisposedException">
 667    /// The Zip file has been closed.
 668    /// </exception>
 669    public ZipEntry GetEntry(string name)
 670    {
 671      if (isDisposed_) {
 672        throw new ObjectDisposedException("ZipFile");
 673      }
 674
 675      int index = FindEntry(name, true);
 676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;
 677    }
 678
 679    /// <summary>
 680    /// Gets an input stream for reading the given zip entry data in an uncompressed form.
 681    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
 682    /// </summary>
 683    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
 684    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
 685    /// <exception cref="ObjectDisposedException">
 686    /// The ZipFile has already been closed
 687    /// </exception>
 688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 689    /// The compression method for the entry is unknown
 690    /// </exception>
 691    /// <exception cref="IndexOutOfRangeException">
 692    /// The entry is not found in the ZipFile
 693    /// </exception>
 694    public Stream GetInputStream(ZipEntry entry)
 695    {
 696      if (entry == null) {
 697        throw new ArgumentNullException(nameof(entry));
 698      }
 699
 700      if (isDisposed_) {
 701        throw new ObjectDisposedException("ZipFile");
 702      }
 703
 704      long index = entry.ZipFileIndex;
 705      if ((index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name)) {
 706        index = FindEntry(entry.Name, true);
 707        if (index < 0) {
 708          throw new ZipException("Entry cannot be found");
 709        }
 710      }
 711      return GetInputStream(index);
 712    }
 713
 714    /// <summary>
 715    /// Creates an input stream reading a zip entry
 716    /// </summary>
 717    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
 718    /// <returns>
 719    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>
 720    /// </returns>
 721    /// <exception cref="ObjectDisposedException">
 722    /// The ZipFile has already been closed
 723    /// </exception>
 724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 725    /// The compression method for the entry is unknown
 726    /// </exception>
 727    /// <exception cref="IndexOutOfRangeException">
 728    /// The entry is not found in the ZipFile
 729    /// </exception>
 730    public Stream GetInputStream(long entryIndex)
 731    {
 732      if (isDisposed_) {
 733        throw new ObjectDisposedException("ZipFile");
 734      }
 735
 736      long start = LocateEntry(entries_[entryIndex]);
 737      CompressionMethod method = entries_[entryIndex].CompressionMethod;
 738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);
 739
 740      if (entries_[entryIndex].IsCrypted == true) {
 741        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);
 742        if (result == null) {
 743          throw new ZipException("Unable to decrypt this entry");
 744        }
 745      }
 746
 747      switch (method) {
 748        case CompressionMethod.Stored:
 749          // read as is.
 750          break;
 751
 752        case CompressionMethod.Deflated:
 753          // No need to worry about ownership and closing as underlying stream close does nothing.
 754          result = new InflaterInputStream(result, new Inflater(true));
 755          break;
 756
 757        default:
 758          throw new ZipException("Unsupported compression method " + method);
 759      }
 760
 761      return result;
 762    }
 763
 764    #endregion
 765
 766    #region Archive Testing
 767    /// <summary>
 768    /// Test an archive for integrity/validity
 769    /// </summary>
 770    /// <param name="testData">Perform low level data Crc check</param>
 771    /// <returns>true if all tests pass, false otherwise</returns>
 772    /// <remarks>Testing will terminate on the first error found.</remarks>
 773    public bool TestArchive(bool testData)
 774    {
 775      return TestArchive(testData, TestStrategy.FindFirstError, null);
 776    }
 777
 778    /// <summary>
 779    /// Test an archive for integrity/validity
 780    /// </summary>
 781    /// <param name="testData">Perform low level data Crc check</param>
 782    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
 783    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
 784    /// <returns>true if all tests pass, false otherwise</returns>
 785    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>
 786    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
 787    {
 788      if (isDisposed_) {
 789        throw new ObjectDisposedException("ZipFile");
 790      }
 791
 792      var status = new TestStatus(this);
 793
 794      if (resultHandler != null) {
 795        resultHandler(status, null);
 796      }
 797
 798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;
 799
 800      bool testing = true;
 801
 802      try {
 803        int entryIndex = 0;
 804
 805        while (testing && (entryIndex < Count)) {
 806          if (resultHandler != null) {
 807            status.SetEntry(this[entryIndex]);
 808            status.SetOperation(TestOperation.EntryHeader);
 809            resultHandler(status, null);
 810          }
 811
 812          try {
 813            TestLocalHeader(this[entryIndex], test);
 814          } catch (ZipException ex) {
 815            status.AddError();
 816
 817            if (resultHandler != null) {
 818              resultHandler(status,
 819                string.Format("Exception during test - '{0}'", ex.Message));
 820            }
 821
 822            testing &= strategy != TestStrategy.FindFirstError;
 823          }
 824
 825          if (testing && testData && this[entryIndex].IsFile) {
 826            if (resultHandler != null) {
 827              status.SetOperation(TestOperation.EntryData);
 828              resultHandler(status, null);
 829            }
 830
 831            var crc = new Crc32();
 832
 833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {
 834
 835              byte[] buffer = new byte[4096];
 836              long totalBytes = 0;
 837              int bytesRead;
 838              while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
 839                crc.Update(buffer, 0, bytesRead);
 840
 841                if (resultHandler != null) {
 842                  totalBytes += bytesRead;
 843                  status.SetBytesTested(totalBytes);
 844                  resultHandler(status, null);
 845                }
 846              }
 847            }
 848
 849            if (this[entryIndex].Crc != crc.Value) {
 850              status.AddError();
 851
 852              if (resultHandler != null) {
 853                resultHandler(status, "CRC mismatch");
 854              }
 855
 856              testing &= strategy != TestStrategy.FindFirstError;
 857            }
 858
 859            if ((this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 860              var helper = new ZipHelperStream(baseStream_);
 861              var data = new DescriptorData();
 862              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
 863              if (this[entryIndex].Crc != data.Crc) {
 864                status.AddError();
 865              }
 866
 867              if (this[entryIndex].CompressedSize != data.CompressedSize) {
 868                status.AddError();
 869              }
 870
 871              if (this[entryIndex].Size != data.Size) {
 872                status.AddError();
 873              }
 874            }
 875          }
 876
 877          if (resultHandler != null) {
 878            status.SetOperation(TestOperation.EntryComplete);
 879            resultHandler(status, null);
 880          }
 881
 882          entryIndex += 1;
 883        }
 884
 885        if (resultHandler != null) {
 886          status.SetOperation(TestOperation.MiscellaneousTests);
 887          resultHandler(status, null);
 888        }
 889
 890        // TODO: the 'Corrina Johns' test where local headers are missing from
 891        // the central directory.  They are therefore invisible to many archivers.
 892      } catch (Exception ex) {
 893        status.AddError();
 894
 895        if (resultHandler != null) {
 896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
 897        }
 898      }
 899
 900      if (resultHandler != null) {
 901        status.SetOperation(TestOperation.Complete);
 902        status.SetEntry(null);
 903        resultHandler(status, null);
 904      }
 905
 906      return (status.ErrorCount == 0);
 907    }
 908
 909    [Flags]
 910    enum HeaderTest
 911    {
 912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted
 913      Header = 0x02,     // Check that this header contents are valid
 914    }
 915
 916    /// <summary>
 917    /// Test a local header against that provided from the central directory
 918    /// </summary>
 919    /// <param name="entry">
 920    /// The entry to test against
 921    /// </param>
 922    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
 923    /// <returns>The offset of the entries data in the file</returns>
 924    long TestLocalHeader(ZipEntry entry, HeaderTest tests)
 925    {
 926      lock (baseStream_) {
 927        bool testHeader = (tests & HeaderTest.Header) != 0;
 928        bool testData = (tests & HeaderTest.Extract) != 0;
 929
 930        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
 931        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
 932          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)
 933        }
 934
 935        var extractVersion = (short)(ReadLEUshort() & 0x00ff);
 936        var localFlags = (short)ReadLEUshort();
 937        var compressionMethod = (short)ReadLEUshort();
 938        var fileTime = (short)ReadLEUshort();
 939        var fileDate = (short)ReadLEUshort();
 940        uint crcValue = ReadLEUint();
 941        long compressedSize = ReadLEUint();
 942        long size = ReadLEUint();
 943        int storedNameLength = ReadLEUshort();
 944        int extraDataLength = ReadLEUshort();
 945
 946        byte[] nameData = new byte[storedNameLength];
 947        StreamUtils.ReadFully(baseStream_, nameData);
 948
 949        byte[] extraData = new byte[extraDataLength];
 950        StreamUtils.ReadFully(baseStream_, extraData);
 951
 952        var localExtraData = new ZipExtraData(extraData);
 953
 954        // Extra data / zip64 checks
 955        if (localExtraData.Find(1)) {
 956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
 957          // and size or compressedSize = MaxValue, due to rogue creators.
 958
 959          size = localExtraData.ReadLong();
 960          compressedSize = localExtraData.ReadLong();
 961
 962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {
 963            // These may be valid if patched later
 964            if ((size != -1) && (size != entry.Size)) {
 965              throw new ZipException("Size invalid for descriptor");
 966            }
 967
 968            if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {
 969              throw new ZipException("Compressed size invalid for descriptor");
 970            }
 971          }
 972        } else {
 973          // No zip64 extra data but entry requires it.
 974          if ((extractVersion >= ZipConstants.VersionZip64) &&
 975            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) {
 976            throw new ZipException("Required Zip64 extended information missing");
 977          }
 978        }
 979
 980        if (testData) {
 981          if (entry.IsFile) {
 982            if (!entry.IsCompressionMethodSupported()) {
 983              throw new ZipException("Compression method not supported");
 984            }
 985
 986            if ((extractVersion > ZipConstants.VersionMadeBy)
 987              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64))) {
 988              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract
 989            }
 990
 991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance
 992              throw new ZipException("The library does not support the zip version required to extract this entry");
 993            }
 994          }
 995        }
 996
 997        if (testHeader) {
 998          if ((extractVersion <= 63) &&   // Ignore later versions as we dont know about them..
 999            (extractVersion != 10) &&
 1000            (extractVersion != 11) &&
 1001            (extractVersion != 20) &&
 1002            (extractVersion != 21) &&
 1003            (extractVersion != 25) &&
 1004            (extractVersion != 27) &&
 1005            (extractVersion != 45) &&
 1006            (extractVersion != 46) &&
 1007            (extractVersion != 50) &&
 1008            (extractVersion != 51) &&
 1009            (extractVersion != 52) &&
 1010            (extractVersion != 61) &&
 1011            (extractVersion != 62) &&
 1012            (extractVersion != 63)
 1013            ) {
 1014            throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersi
 1015          }
 1016
 1017          // Local entry flags dont have reserved bit set on.
 1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R
 1019            throw new ZipException("Reserved bit flags cannot be set.");
 1020          }
 1021
 1022          // Encryption requires extract version >= 20
 1023          if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) {
 1024            throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})
 1025          }
 1026
 1027          // Strong encryption requires encryption flag to be set and extract version >= 50.
 1028          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1029            if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) {
 1030              throw new ZipException("Strong encryption flag set but encryption flag is not set");
 1031            }
 1032
 1033            if (extractVersion < 50) {
 1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0
 1035            }
 1036          }
 1037
 1038          // Patched entries require extract version >= 27
 1039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {
 1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
 1041          }
 1042
 1043          // Central header flags match local entry flags.
 1044          if (localFlags != entry.Flags) {
 1045            throw new ZipException("Central header/local header flags mismatch");
 1046          }
 1047
 1048          // Central header compression method matches local entry
 1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {
 1050            throw new ZipException("Central header/local header compression method mismatch");
 1051          }
 1052
 1053          if (entry.Version != extractVersion) {
 1054            throw new ZipException("Extract version mismatch");
 1055          }
 1056
 1057          // Strong encryption and extract version match
 1058          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1059            if (extractVersion < 62) {
 1060              throw new ZipException("Strong encryption flag set but version not high enough");
 1061            }
 1062          }
 1063
 1064          if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) {
 1065            if ((fileTime != 0) || (fileDate != 0)) {
 1066              throw new ZipException("Header masked set but date/time values non-zero");
 1067            }
 1068          }
 1069
 1070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
 1071            if (crcValue != (uint)entry.Crc) {
 1072              throw new ZipException("Central header/local header crc mismatch");
 1073            }
 1074          }
 1075
 1076          // Crc valid for empty entry.
 1077          // This will also apply to streamed entries where size isnt known and the header cant be patched
 1078          if ((size == 0) && (compressedSize == 0)) {
 1079            if (crcValue != 0) {
 1080              throw new ZipException("Invalid CRC for empty entry");
 1081            }
 1082          }
 1083
 1084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str
 1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
 1086          if (entry.Name.Length > storedNameLength) {
 1087            throw new ZipException("File name length mismatch");
 1088          }
 1089
 1090          // Name data has already been read convert it and compare.
 1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);
 1092
 1093          // Central directory and local entry name match
 1094          if (localName != entry.Name) {
 1095            throw new ZipException("Central header and local header file name mismatch");
 1096          }
 1097
 1098          // Directories have zero actual size but can have compressed size
 1099          if (entry.IsDirectory) {
 1100            if (size > 0) {
 1101              throw new ZipException("Directory cannot have size");
 1102            }
 1103
 1104            // There may be other cases where the compressed size can be greater than this?
 1105            // If so until details are known we will be strict.
 1106            if (entry.IsCrypted) {
 1107              if (compressedSize > ZipConstants.CryptoHeaderSize + 2) {
 1108                throw new ZipException("Directory compressed size invalid");
 1109              }
 1110            } else if (compressedSize > 2) {
 1111              // When not compressed the directory size can validly be 2 bytes
 1112              // if the true size wasnt known when data was originally being written.
 1113              // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
 1114              throw new ZipException("Directory compressed size invalid");
 1115            }
 1116          }
 1117
 1118          if (!ZipNameTransform.IsValidName(localName, true)) {
 1119            throw new ZipException("Name is invalid");
 1120          }
 1121        }
 1122
 1123        // Tests that apply to both data and header.
 1124
 1125        // Size can be verified only if it is known in the local header.
 1126        // it will always be known in the central header.
 1127        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
 1128          ((size > 0 || compressedSize > 0) && entry.Size > 0)) {
 1129
 1130          if ((size != 0)
 1131            && (size != entry.Size)) {
 1132            throw new ZipException(
 1133              string.Format("Size mismatch between central header({0}) and local header({1})",
 1134                entry.Size, size));
 1135          }
 1136
 1137          if ((compressedSize != 0)
 1138            && (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) {
 1139            throw new ZipException(
 1140              string.Format("Compressed size mismatch between central header({0}) and local header({1})",
 1141              entry.CompressedSize, compressedSize));
 1142          }
 1143        }
 1144
 1145        int extraLength = storedNameLength + extraDataLength;
 1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
 1147      }
 1148    }
 1149
 1150    #endregion
 1151
 1152    #region Updating
 1153
 1154    const int DefaultBufferSize = 4096;
 1155
 1156    /// <summary>
 1157    /// The kind of update to apply.
 1158    /// </summary>
 1159    enum UpdateCommand
 1160    {
 1161      Copy,       // Copy original file contents.
 1162      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.
 1163      Add,        // Add a new file to the archive.
 1164    }
 1165
 1166    #region Properties
 1167    /// <summary>
 1168    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.
 1169    /// </summary>
 1170    public INameTransform NameTransform {
 1171      get {
 1172        return updateEntryFactory_.NameTransform;
 1173      }
 1174
 1175      set {
 1176        updateEntryFactory_.NameTransform = value;
 1177      }
 1178    }
 1179
 1180    /// <summary>
 1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values
 1182    /// during updates.
 1183    /// </summary>
 1184    public IEntryFactory EntryFactory {
 1185      get {
 1186        return updateEntryFactory_;
 1187      }
 1188
 1189      set {
 1190        if (value == null) {
 1191          updateEntryFactory_ = new ZipEntryFactory();
 1192        } else {
 1193          updateEntryFactory_ = value;
 1194        }
 1195      }
 1196    }
 1197
 1198    /// <summary>
 1199    /// Get /set the buffer size to be used when updating this zip file.
 1200    /// </summary>
 1201    public int BufferSize {
 1202      get { return bufferSize_; }
 1203      set {
 1204        if (value < 1024) {
 1205          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");
 1206        }
 1207
 1208        if (bufferSize_ != value) {
 1209          bufferSize_ = value;
 1210          copyBuffer_ = null;
 1211        }
 1212      }
 1213    }
 1214
 1215    /// <summary>
 1216    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.
 1217    /// </summary>
 1218    public bool IsUpdating {
 1219      get { return updates_ != null; }
 1220    }
 1221
 1222    /// <summary>
 1223    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
 1224    /// </summary>
 1225    public UseZip64 UseZip64 {
 1226      get { return useZip64_; }
 1227      set { useZip64_ = value; }
 1228    }
 1229
 1230    #endregion
 1231
 1232    #region Immediate updating
 1233    //    TBD: Direct form of updating
 1234    //
 1235    //    public void Update(IEntryMatcher deleteMatcher)
 1236    //    {
 1237    //    }
 1238    //
 1239    //    public void Update(IScanner addScanner)
 1240    //    {
 1241    //    }
 1242    #endregion
 1243
 1244    #region Deferred Updating
 1245    /// <summary>
 1246    /// Begin updating this <see cref="ZipFile"/> archive.
 1247    /// </summary>
 1248    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p
 1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param
 1250    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1251    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>
 1252    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1253    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)
 1254    {
 1255      if (archiveStorage == null) {
 1256        throw new ArgumentNullException(nameof(archiveStorage));
 1257      }
 1258
 1259      if (dataSource == null) {
 1260        throw new ArgumentNullException(nameof(dataSource));
 1261      }
 1262
 1263      if (isDisposed_) {
 1264        throw new ObjectDisposedException("ZipFile");
 1265      }
 1266
 1267      if (IsEmbeddedArchive) {
 1268        throw new ZipException("Cannot update embedded/SFX archives");
 1269      }
 1270
 1271      archiveStorage_ = archiveStorage;
 1272      updateDataSource_ = dataSource;
 1273
 1274      // NOTE: the baseStream_ may not currently support writing or seeking.
 1275
 1276      updateIndex_ = new Hashtable();
 1277
 1278      updates_ = new ArrayList(entries_.Length);
 1279      foreach (ZipEntry entry in entries_) {
 1280        int index = updates_.Add(new ZipUpdate(entry));
 1281        updateIndex_.Add(entry.Name, index);
 1282      }
 1283
 1284      // We must sort by offset before using offset's calculated sizes
 1285      updates_.Sort(new UpdateComparer());
 1286
 1287      int idx = 0;
 1288      foreach (ZipUpdate update in updates_) {
 1289        //If last entry, there is no next entry offset to use
 1290        if (idx == updates_.Count - 1)
 1291          break;
 1292
 1293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;
 1294        idx++;
 1295      }
 1296      updateCount_ = updates_.Count;
 1297
 1298      contentsEdited_ = false;
 1299      commentEdited_ = false;
 1300      newComment_ = null;
 1301    }
 1302
 1303    /// <summary>
 1304    /// Begin updating to this <see cref="ZipFile"/> archive.
 1305    /// </summary>
 1306    /// <param name="archiveStorage">The storage to use during the update.</param>
 1307    public void BeginUpdate(IArchiveStorage archiveStorage)
 1308    {
 1309      BeginUpdate(archiveStorage, new DynamicDiskDataSource());
 1310    }
 1311
 1312    /// <summary>
 1313    /// Begin updating this <see cref="ZipFile"/> archive.
 1314    /// </summary>
 1315    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>
 1316    /// <seealso cref="CommitUpdate"></seealso>
 1317    /// <seealso cref="AbortUpdate"></seealso>
 1318    public void BeginUpdate()
 1319    {
 1320      if (Name == null) {
 1321        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());
 1322      } else {
 1323        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());
 1324      }
 1325    }
 1326
 1327    /// <summary>
 1328    /// Commit current updates, updating this archive.
 1329    /// </summary>
 1330    /// <seealso cref="BeginUpdate()"></seealso>
 1331    /// <seealso cref="AbortUpdate"></seealso>
 1332    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1333    public void CommitUpdate()
 1334    {
 1335      if (isDisposed_) {
 1336        throw new ObjectDisposedException("ZipFile");
 1337      }
 1338
 1339      CheckUpdating();
 1340
 1341      try {
 1342        updateIndex_.Clear();
 1343        updateIndex_ = null;
 1344
 1345        if (contentsEdited_) {
 1346          RunUpdates();
 1347        } else if (commentEdited_) {
 1348          UpdateCommentOnly();
 1349        } else {
 1350          // Create an empty archive if none existed originally.
 1351          if (entries_.Length == 0) {
 1352            byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 1353            using (ZipHelperStream zhs = new ZipHelperStream(baseStream_)) {
 1354              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
 1355            }
 1356          }
 1357        }
 1358
 1359      } finally {
 1360        PostUpdateCleanup();
 1361      }
 1362    }
 1363
 1364    /// <summary>
 1365    /// Abort updating leaving the archive unchanged.
 1366    /// </summary>
 1367    /// <seealso cref="BeginUpdate()"></seealso>
 1368    /// <seealso cref="CommitUpdate"></seealso>
 1369    public void AbortUpdate()
 1370    {
 1371      PostUpdateCleanup();
 1372    }
 1373
 1374    /// <summary>
 1375    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.
 1376    /// </summary>
 1377    /// <param name="comment">The comment to record.</param>
 1378    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1379    public void SetComment(string comment)
 1380    {
 1381      if (isDisposed_) {
 1382        throw new ObjectDisposedException("ZipFile");
 1383      }
 1384
 1385      CheckUpdating();
 1386
 1387      newComment_ = new ZipString(comment);
 1388
 1389      if (newComment_.RawLength > 0xffff) {
 1390        newComment_ = null;
 1391        throw new ZipException("Comment length exceeds maximum - 65535");
 1392      }
 1393
 1394      // We dont take account of the original and current comment appearing to be the same
 1395      // as encoding may be different.
 1396      commentEdited_ = true;
 1397    }
 1398
 1399    #endregion
 1400
 1401    #region Adding Entries
 1402
 1403    void AddUpdate(ZipUpdate update)
 1404    {
 1405      contentsEdited_ = true;
 1406
 1407      int index = FindExistingUpdate(update.Entry.Name);
 1408
 1409      if (index >= 0) {
 1410        if (updates_[index] == null) {
 1411          updateCount_ += 1;
 1412        }
 1413
 1414        // Direct replacement is faster than delete and add.
 1415        updates_[index] = update;
 1416      } else {
 1417        index = updates_.Add(update);
 1418        updateCount_ += 1;
 1419        updateIndex_.Add(update.Entry.Name, index);
 1420      }
 1421    }
 1422
 1423    /// <summary>
 1424    /// Add a new entry to the archive.
 1425    /// </summary>
 1426    /// <param name="fileName">The name of the file to add.</param>
 1427    /// <param name="compressionMethod">The compression method to use.</param>
 1428    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>
 1429    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1430    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1431    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>
 1432    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText)
 1433    {
 1434      if (fileName == null) {
 1435        throw new ArgumentNullException(nameof(fileName));
 1436      }
 1437
 1438      if (isDisposed_) {
 1439        throw new ObjectDisposedException("ZipFile");
 1440      }
 1441
 1442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1444      }
 1445
 1446      CheckUpdating();
 1447      contentsEdited_ = true;
 1448
 1449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1450      entry.IsUnicodeText = useUnicodeText;
 1451      entry.CompressionMethod = compressionMethod;
 1452
 1453      AddUpdate(new ZipUpdate(fileName, entry));
 1454    }
 1455
 1456    /// <summary>
 1457    /// Add a new entry to the archive.
 1458    /// </summary>
 1459    /// <param name="fileName">The name of the file to add.</param>
 1460    /// <param name="compressionMethod">The compression method to use.</param>
 1461    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>
 1462    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>
 1463    public void Add(string fileName, CompressionMethod compressionMethod)
 1464    {
 1465      if (fileName == null) {
 1466        throw new ArgumentNullException(nameof(fileName));
 1467      }
 1468
 1469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1471      }
 1472
 1473      CheckUpdating();
 1474      contentsEdited_ = true;
 1475
 1476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1477      entry.CompressionMethod = compressionMethod;
 1478      AddUpdate(new ZipUpdate(fileName, entry));
 1479    }
 1480
 1481    /// <summary>
 1482    /// Add a file to the archive.
 1483    /// </summary>
 1484    /// <param name="fileName">The name of the file to add.</param>
 1485    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1486    public void Add(string fileName)
 1487    {
 1488      if (fileName == null) {
 1489        throw new ArgumentNullException(nameof(fileName));
 1490      }
 1491
 1492      CheckUpdating();
 1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));
 1494    }
 1495
 1496    /// <summary>
 1497    /// Add a file to the archive.
 1498    /// </summary>
 1499    /// <param name="fileName">The name of the file to add.</param>
 1500    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>
 1501    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1502    public void Add(string fileName, string entryName)
 1503    {
 1504      if (fileName == null) {
 1505        throw new ArgumentNullException(nameof(fileName));
 1506      }
 1507
 1508      if (entryName == null) {
 1509        throw new ArgumentNullException(nameof(entryName));
 1510      }
 1511
 1512      CheckUpdating();
 1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));
 1514    }
 1515
 1516
 1517    /// <summary>
 1518    /// Add a file entry with data.
 1519    /// </summary>
 1520    /// <param name="dataSource">The source of the data for this entry.</param>
 1521    /// <param name="entryName">The name to give to the entry.</param>
 1522    public void Add(IStaticDataSource dataSource, string entryName)
 1523    {
 1524      if (dataSource == null) {
 1525        throw new ArgumentNullException(nameof(dataSource));
 1526      }
 1527
 1528      if (entryName == null) {
 1529        throw new ArgumentNullException(nameof(entryName));
 1530      }
 1531
 1532      CheckUpdating();
 1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));
 1534    }
 1535
 1536    /// <summary>
 1537    /// Add a file entry with data.
 1538    /// </summary>
 1539    /// <param name="dataSource">The source of the data for this entry.</param>
 1540    /// <param name="entryName">The name to give to the entry.</param>
 1541    /// <param name="compressionMethod">The compression method to use.</param>
 1542    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 1543    {
 1544      if (dataSource == null) {
 1545        throw new ArgumentNullException(nameof(dataSource));
 1546      }
 1547
 1548      if (entryName == null) {
 1549        throw new ArgumentNullException(nameof(entryName));
 1550      }
 1551
 1552      CheckUpdating();
 1553
 1554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1555      entry.CompressionMethod = compressionMethod;
 1556
 1557      AddUpdate(new ZipUpdate(dataSource, entry));
 1558    }
 1559
 1560    /// <summary>
 1561    /// Add a file entry with data.
 1562    /// </summary>
 1563    /// <param name="dataSource">The source of the data for this entry.</param>
 1564    /// <param name="entryName">The name to give to the entry.</param>
 1565    /// <param name="compressionMethod">The compression method to use.</param>
 1566    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>
 1567    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode
 1568    {
 1569      if (dataSource == null) {
 1570        throw new ArgumentNullException(nameof(dataSource));
 1571      }
 1572
 1573      if (entryName == null) {
 1574        throw new ArgumentNullException(nameof(entryName));
 1575      }
 1576
 1577      CheckUpdating();
 1578
 1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1580      entry.IsUnicodeText = useUnicodeText;
 1581      entry.CompressionMethod = compressionMethod;
 1582
 1583      AddUpdate(new ZipUpdate(dataSource, entry));
 1584    }
 1585
 1586    /// <summary>
 1587    /// Add a <see cref="ZipEntry"/> that contains no data.
 1588    /// </summary>
 1589    /// <param name="entry">The entry to add.</param>
 1590    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
 1591    public void Add(ZipEntry entry)
 1592    {
 1593      if (entry == null) {
 1594        throw new ArgumentNullException(nameof(entry));
 1595      }
 1596
 1597      CheckUpdating();
 1598
 1599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {
 1600        throw new ZipException("Entry cannot have any data");
 1601      }
 1602
 1603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
 1604    }
 1605
 1606    /// <summary>
 1607    /// Add a directory entry to the archive.
 1608    /// </summary>
 1609    /// <param name="directoryName">The directory to add.</param>
 1610    public void AddDirectory(string directoryName)
 1611    {
 1612      if (directoryName == null) {
 1613        throw new ArgumentNullException(nameof(directoryName));
 1614      }
 1615
 1616      CheckUpdating();
 1617
 1618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);
 1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));
 1620    }
 1621
 1622    #endregion
 1623
 1624    #region Modifying Entries
 1625    /* Modify not yet ready for public consumption.
 1626       Direct modification of an entry should not overwrite original data before its read.
 1627       Safe mode is trivial in this sense.
 1628        public void Modify(ZipEntry original, ZipEntry updated)
 1629        {
 1630          if ( original == null ) {
 1631            throw new ArgumentNullException("original");
 1632          }
 1633
 1634          if ( updated == null ) {
 1635            throw new ArgumentNullException("updated");
 1636          }
 1637
 1638          CheckUpdating();
 1639          contentsEdited_ = true;
 1640          updates_.Add(new ZipUpdate(original, updated));
 1641        }
 1642    */
 1643    #endregion
 1644
 1645    #region Deleting Entries
 1646    /// <summary>
 1647    /// Delete an entry by name
 1648    /// </summary>
 1649    /// <param name="fileName">The filename to delete</param>
 1650    /// <returns>True if the entry was found and deleted; false otherwise.</returns>
 1651    public bool Delete(string fileName)
 1652    {
 1653      if (fileName == null) {
 1654        throw new ArgumentNullException(nameof(fileName));
 1655      }
 1656
 1657      CheckUpdating();
 1658
 1659      bool result = false;
 1660      int index = FindExistingUpdate(fileName);
 1661      if ((index >= 0) && (updates_[index] != null)) {
 1662        result = true;
 1663        contentsEdited_ = true;
 1664        updates_[index] = null;
 1665        updateCount_ -= 1;
 1666      } else {
 1667        throw new ZipException("Cannot find entry to delete");
 1668      }
 1669      return result;
 1670    }
 1671
 1672    /// <summary>
 1673    /// Delete a <see cref="ZipEntry"/> from the archive.
 1674    /// </summary>
 1675    /// <param name="entry">The entry to delete.</param>
 1676    public void Delete(ZipEntry entry)
 1677    {
 1678      if (entry == null) {
 1679        throw new ArgumentNullException(nameof(entry));
 1680      }
 1681
 1682      CheckUpdating();
 1683
 1684      int index = FindExistingUpdate(entry);
 1685      if (index >= 0) {
 1686        contentsEdited_ = true;
 1687        updates_[index] = null;
 1688        updateCount_ -= 1;
 1689      } else {
 1690        throw new ZipException("Cannot find entry to delete");
 1691      }
 1692    }
 1693
 1694    #endregion
 1695
 1696    #region Update Support
 1697
 1698    #region Writing Values/Headers
 1699    void WriteLEShort(int value)
 1700    {
 1701      baseStream_.WriteByte((byte)(value & 0xff));
 1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));
 1703    }
 1704
 1705    /// <summary>
 1706    /// Write an unsigned short in little endian byte order.
 1707    /// </summary>
 1708    void WriteLEUshort(ushort value)
 1709    {
 1710      baseStream_.WriteByte((byte)(value & 0xff));
 1711      baseStream_.WriteByte((byte)(value >> 8));
 1712    }
 1713
 1714    /// <summary>
 1715    /// Write an int in little endian byte order.
 1716    /// </summary>
 1717    void WriteLEInt(int value)
 1718    {
 1719      WriteLEShort(value & 0xffff);
 1720      WriteLEShort(value >> 16);
 1721    }
 1722
 1723    /// <summary>
 1724    /// Write an unsigned int in little endian byte order.
 1725    /// </summary>
 1726    void WriteLEUint(uint value)
 1727    {
 1728      WriteLEUshort((ushort)(value & 0xffff));
 1729      WriteLEUshort((ushort)(value >> 16));
 1730    }
 1731
 1732    /// <summary>
 1733    /// Write a long in little endian byte order.
 1734    /// </summary>
 1735    void WriteLeLong(long value)
 1736    {
 1737      WriteLEInt((int)(value & 0xffffffff));
 1738      WriteLEInt((int)(value >> 32));
 1739    }
 1740
 1741    void WriteLEUlong(ulong value)
 1742    {
 1743      WriteLEUint((uint)(value & 0xffffffff));
 1744      WriteLEUint((uint)(value >> 32));
 1745    }
 1746
 1747    void WriteLocalEntryHeader(ZipUpdate update)
 1748    {
 1749      ZipEntry entry = update.OutEntry;
 1750
 1751      // TODO: Local offset will require adjusting for multi-disk zip files.
 1752      entry.Offset = baseStream_.Position;
 1753
 1754      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
 1755      if (update.Command != UpdateCommand.Copy) {
 1756        if (entry.CompressionMethod == CompressionMethod.Deflated) {
 1757          if (entry.Size == 0) {
 1758            // No need to compress - no data.
 1759            entry.CompressedSize = entry.Size;
 1760            entry.Crc = 0;
 1761            entry.CompressionMethod = CompressionMethod.Stored;
 1762          }
 1763        } else if (entry.CompressionMethod == CompressionMethod.Stored) {
 1764          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
 1765        }
 1766
 1767        if (HaveKeys) {
 1768          entry.IsCrypted = true;
 1769          if (entry.Crc < 0) {
 1770            entry.Flags |= (int)GeneralBitFlags.Descriptor;
 1771          }
 1772        } else {
 1773          entry.IsCrypted = false;
 1774        }
 1775
 1776        switch (useZip64_) {
 1777          case UseZip64.Dynamic:
 1778            if (entry.Size < 0) {
 1779              entry.ForceZip64();
 1780            }
 1781            break;
 1782
 1783          case UseZip64.On:
 1784            entry.ForceZip64();
 1785            break;
 1786
 1787          case UseZip64.Off:
 1788            // Do nothing.  The entry itself may be using Zip64 independantly.
 1789            break;
 1790        }
 1791      }
 1792
 1793      // Write the local file header
 1794      WriteLEInt(ZipConstants.LocalHeaderSignature);
 1795
 1796      WriteLEShort(entry.Version);
 1797      WriteLEShort(entry.Flags);
 1798
 1799      WriteLEShort((byte)entry.CompressionMethod);
 1800      WriteLEInt((int)entry.DosTime);
 1801
 1802      if (!entry.HasCrc) {
 1803        // Note patch address for updating CRC later.
 1804        update.CrcPatchOffset = baseStream_.Position;
 1805        WriteLEInt((int)0);
 1806      } else {
 1807        WriteLEInt(unchecked((int)entry.Crc));
 1808      }
 1809
 1810      if (entry.LocalHeaderRequiresZip64) {
 1811        WriteLEInt(-1);
 1812        WriteLEInt(-1);
 1813      } else {
 1814        if ((entry.CompressedSize < 0) || (entry.Size < 0)) {
 1815          update.SizePatchOffset = baseStream_.Position;
 1816        }
 1817
 1818        WriteLEInt((int)entry.CompressedSize);
 1819        WriteLEInt((int)entry.Size);
 1820      }
 1821
 1822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1823
 1824      if (name.Length > 0xFFFF) {
 1825        throw new ZipException("Entry name too long.");
 1826      }
 1827
 1828      var ed = new ZipExtraData(entry.ExtraData);
 1829
 1830      if (entry.LocalHeaderRequiresZip64) {
 1831        ed.StartNewEntry();
 1832
 1833        // Local entry header always includes size and compressed size.
 1834        // NOTE the order of these fields is reversed when compared to the normal headers!
 1835        ed.AddLeLong(entry.Size);
 1836        ed.AddLeLong(entry.CompressedSize);
 1837        ed.AddNewEntry(1);
 1838      } else {
 1839        ed.Delete(1);
 1840      }
 1841
 1842      entry.ExtraData = ed.GetEntryData();
 1843
 1844      WriteLEShort(name.Length);
 1845      WriteLEShort(entry.ExtraData.Length);
 1846
 1847      if (name.Length > 0) {
 1848        baseStream_.Write(name, 0, name.Length);
 1849      }
 1850
 1851      if (entry.LocalHeaderRequiresZip64) {
 1852        if (!ed.Find(1)) {
 1853          throw new ZipException("Internal error cannot find extra data");
 1854        }
 1855
 1856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
 1857      }
 1858
 1859      if (entry.ExtraData.Length > 0) {
 1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
 1861      }
 1862    }
 1863
 1864    int WriteCentralDirectoryHeader(ZipEntry entry)
 1865    {
 1866      if (entry.CompressedSize < 0) {
 1867        throw new ZipException("Attempt to write central directory entry with unknown csize");
 1868      }
 1869
 1870      if (entry.Size < 0) {
 1871        throw new ZipException("Attempt to write central directory entry with unknown size");
 1872      }
 1873
 1874      if (entry.Crc < 0) {
 1875        throw new ZipException("Attempt to write central directory entry with unknown crc");
 1876      }
 1877
 1878      // Write the central file header
 1879      WriteLEInt(ZipConstants.CentralHeaderSignature);
 1880
 1881      // Version made by
 1882      WriteLEShort(ZipConstants.VersionMadeBy);
 1883
 1884      // Version required to extract
 1885      WriteLEShort(entry.Version);
 1886
 1887      WriteLEShort(entry.Flags);
 1888
 1889      unchecked {
 1890        WriteLEShort((byte)entry.CompressionMethod);
 1891        WriteLEInt((int)entry.DosTime);
 1892        WriteLEInt((int)entry.Crc);
 1893      }
 1894
 1895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {
 1896        WriteLEInt(-1);
 1897      } else {
 1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
 1899      }
 1900
 1901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {
 1902        WriteLEInt(-1);
 1903      } else {
 1904        WriteLEInt((int)entry.Size);
 1905      }
 1906
 1907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1908
 1909      if (name.Length > 0xFFFF) {
 1910        throw new ZipException("Entry name is too long.");
 1911      }
 1912
 1913      WriteLEShort(name.Length);
 1914
 1915      // Central header extra data is different to local header version so regenerate.
 1916      var ed = new ZipExtraData(entry.ExtraData);
 1917
 1918      if (entry.CentralHeaderRequiresZip64) {
 1919        ed.StartNewEntry();
 1920
 1921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1922          ed.AddLeLong(entry.Size);
 1923        }
 1924
 1925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1926          ed.AddLeLong(entry.CompressedSize);
 1927        }
 1928
 1929        if (entry.Offset >= 0xffffffff) {
 1930          ed.AddLeLong(entry.Offset);
 1931        }
 1932
 1933        // Number of disk on which this file starts isnt supported and is never written here.
 1934        ed.AddNewEntry(1);
 1935      } else {
 1936        // Should have already be done when local header was added.
 1937        ed.Delete(1);
 1938      }
 1939
 1940      byte[] centralExtraData = ed.GetEntryData();
 1941
 1942      WriteLEShort(centralExtraData.Length);
 1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);
 1944
 1945      WriteLEShort(0);    // disk number
 1946      WriteLEShort(0);    // internal file attributes
 1947
 1948      // External file attributes...
 1949      if (entry.ExternalFileAttributes != -1) {
 1950        WriteLEInt(entry.ExternalFileAttributes);
 1951      } else {
 1952        if (entry.IsDirectory) {
 1953          WriteLEUint(16);
 1954        } else {
 1955          WriteLEUint(0);
 1956        }
 1957      }
 1958
 1959      if (entry.Offset >= 0xffffffff) {
 1960        WriteLEUint(0xffffffff);
 1961      } else {
 1962        WriteLEUint((uint)(int)entry.Offset);
 1963      }
 1964
 1965      if (name.Length > 0) {
 1966        baseStream_.Write(name, 0, name.Length);
 1967      }
 1968
 1969      if (centralExtraData.Length > 0) {
 1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
 1971      }
 1972
 1973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];
 1974
 1975      if (rawComment.Length > 0) {
 1976        baseStream_.Write(rawComment, 0, rawComment.Length);
 1977      }
 1978
 1979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
 1980    }
 1981    #endregion
 1982
 1983    void PostUpdateCleanup()
 1984    {
 1985      updateDataSource_ = null;
 1986      updates_ = null;
 1987      updateIndex_ = null;
 1988
 1989      if (archiveStorage_ != null) {
 1990        archiveStorage_.Dispose();
 1991        archiveStorage_ = null;
 1992      }
 1993    }
 1994
 1995    string GetTransformedFileName(string name)
 1996    {
 1997      INameTransform transform = NameTransform;
 1998      return (transform != null) ?
 1999        transform.TransformFile(name) :
 2000        name;
 2001    }
 2002
 2003    string GetTransformedDirectoryName(string name)
 2004    {
 2005      INameTransform transform = NameTransform;
 2006      return (transform != null) ?
 2007        transform.TransformDirectory(name) :
 2008        name;
 2009    }
 2010
 2011    /// <summary>
 2012    /// Get a raw memory buffer.
 2013    /// </summary>
 2014    /// <returns>Returns a raw memory buffer.</returns>
 2015    byte[] GetBuffer()
 2016    {
 2017      if (copyBuffer_ == null) {
 2018        copyBuffer_ = new byte[bufferSize_];
 2019      }
 2020      return copyBuffer_;
 2021    }
 2022
 2023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)
 2024    {
 2025      int bytesToCopy = GetDescriptorSize(update);
 2026
 2027      if (bytesToCopy > 0) {
 2028        byte[] buffer = GetBuffer();
 2029
 2030        while (bytesToCopy > 0) {
 2031          int readSize = Math.Min(buffer.Length, bytesToCopy);
 2032
 2033          int bytesRead = source.Read(buffer, 0, readSize);
 2034          if (bytesRead > 0) {
 2035            dest.Write(buffer, 0, bytesRead);
 2036            bytesToCopy -= bytesRead;
 2037          } else {
 2038            throw new ZipException("Unxpected end of stream");
 2039          }
 2040        }
 2041      }
 2042    }
 2043
 2044    void CopyBytes(ZipUpdate update, Stream destination, Stream source,
 2045      long bytesToCopy, bool updateCrc)
 2046    {
 2047      if (destination == source) {
 2048        throw new InvalidOperationException("Destination and source are the same");
 2049      }
 2050
 2051      // NOTE: Compressed size is updated elsewhere.
 2052      var crc = new Crc32();
 2053      byte[] buffer = GetBuffer();
 2054
 2055      long targetBytes = bytesToCopy;
 2056      long totalBytesRead = 0;
 2057
 2058      int bytesRead;
 2059      do {
 2060        int readSize = buffer.Length;
 2061
 2062        if (bytesToCopy < readSize) {
 2063          readSize = (int)bytesToCopy;
 2064        }
 2065
 2066        bytesRead = source.Read(buffer, 0, readSize);
 2067        if (bytesRead > 0) {
 2068          if (updateCrc) {
 2069            crc.Update(buffer, 0, bytesRead);
 2070          }
 2071          destination.Write(buffer, 0, bytesRead);
 2072          bytesToCopy -= bytesRead;
 2073          totalBytesRead += bytesRead;
 2074        }
 2075      }
 2076      while ((bytesRead > 0) && (bytesToCopy > 0));
 2077
 2078      if (totalBytesRead != targetBytes) {
 2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2080      }
 2081
 2082      if (updateCrc) {
 2083        update.OutEntry.Crc = crc.Value;
 2084      }
 2085    }
 2086
 2087    /// <summary>
 2088    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
 2089    /// </summary>
 2090    /// <param name="update">The update to get the size for.</param>
 2091    /// <returns>The descriptor size, zero if there isnt one.</returns>
 2092    int GetDescriptorSize(ZipUpdate update)
 2093    {
 2094      int result = 0;
 2095      if ((update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 2096        result = ZipConstants.DataDescriptorSize - 4;
 2097        if (update.Entry.LocalHeaderRequiresZip64) {
 2098          result = ZipConstants.Zip64DataDescriptorSize - 4;
 2099        }
 2100      }
 2101      return result;
 2102    }
 2103
 2104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
 2105    {
 2106      int bytesToCopy = GetDescriptorSize(update);
 2107
 2108      while (bytesToCopy > 0) {
 2109        var readSize = (int)bytesToCopy;
 2110        byte[] buffer = GetBuffer();
 2111
 2112        stream.Position = sourcePosition;
 2113        int bytesRead = stream.Read(buffer, 0, readSize);
 2114        if (bytesRead > 0) {
 2115          stream.Position = destinationPosition;
 2116          stream.Write(buffer, 0, bytesRead);
 2117          bytesToCopy -= bytesRead;
 2118          destinationPosition += bytesRead;
 2119          sourcePosition += bytesRead;
 2120        } else {
 2121          throw new ZipException("Unxpected end of stream");
 2122        }
 2123      }
 2124    }
 2125
 2126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou
 2127    {
 2128      long bytesToCopy = update.Entry.CompressedSize;
 2129
 2130      // NOTE: Compressed size is updated elsewhere.
 2131      var crc = new Crc32();
 2132      byte[] buffer = GetBuffer();
 2133
 2134      long targetBytes = bytesToCopy;
 2135      long totalBytesRead = 0;
 2136
 2137      int bytesRead;
 2138      do {
 2139        int readSize = buffer.Length;
 2140
 2141        if (bytesToCopy < readSize) {
 2142          readSize = (int)bytesToCopy;
 2143        }
 2144
 2145        stream.Position = sourcePosition;
 2146        bytesRead = stream.Read(buffer, 0, readSize);
 2147        if (bytesRead > 0) {
 2148          if (updateCrc) {
 2149            crc.Update(buffer, 0, bytesRead);
 2150          }
 2151          stream.Position = destinationPosition;
 2152          stream.Write(buffer, 0, bytesRead);
 2153
 2154          destinationPosition += bytesRead;
 2155          sourcePosition += bytesRead;
 2156          bytesToCopy -= bytesRead;
 2157          totalBytesRead += bytesRead;
 2158        }
 2159      }
 2160      while ((bytesRead > 0) && (bytesToCopy > 0));
 2161
 2162      if (totalBytesRead != targetBytes) {
 2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2164      }
 2165
 2166      if (updateCrc) {
 2167        update.OutEntry.Crc = crc.Value;
 2168      }
 2169    }
 2170
 2171    int FindExistingUpdate(ZipEntry entry)
 2172    {
 2173      int result = -1;
 2174      string convertedName = GetTransformedFileName(entry.Name);
 2175
 2176      if (updateIndex_.ContainsKey(convertedName)) {
 2177        result = (int)updateIndex_[convertedName];
 2178      }
 2179      /*
 2180            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2181            // for CF?
 2182            for (int index = 0; index < updates_.Count; ++index)
 2183            {
 2184              ZipUpdate zu = ( ZipUpdate )updates_[index];
 2185              if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
 2186                (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
 2187                result = index;
 2188                break;
 2189              }
 2190            }
 2191       */
 2192      return result;
 2193    }
 2194
 2195    int FindExistingUpdate(string fileName)
 2196    {
 2197      int result = -1;
 2198
 2199      string convertedName = GetTransformedFileName(fileName);
 2200
 2201      if (updateIndex_.ContainsKey(convertedName)) {
 2202        result = (int)updateIndex_[convertedName];
 2203      }
 2204
 2205      /*
 2206            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2207            // for CF?
 2208            for ( int index = 0; index < updates_.Count; ++index ) {
 2209              if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,
 2210                true, CultureInfo.InvariantCulture) == 0 ) {
 2211                result = index;
 2212                break;
 2213              }
 2214            }
 2215       */
 2216
 2217      return result;
 2218    }
 2219
 2220    /// <summary>
 2221    /// Get an output stream for the specified <see cref="ZipEntry"/>
 2222    /// </summary>
 2223    /// <param name="entry">The entry to get an output stream for.</param>
 2224    /// <returns>The output stream obtained for the entry.</returns>
 2225    Stream GetOutputStream(ZipEntry entry)
 2226    {
 2227      Stream result = baseStream_;
 2228
 2229      if (entry.IsCrypted == true) {
 2230        result = CreateAndInitEncryptionStream(result, entry);
 2231      }
 2232
 2233      switch (entry.CompressionMethod) {
 2234        case CompressionMethod.Stored:
 2235          result = new UncompressedStream(result);
 2236          break;
 2237
 2238        case CompressionMethod.Deflated:
 2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));
 2240          dos.IsStreamOwner = false;
 2241          result = dos;
 2242          break;
 2243
 2244        default:
 2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);
 2246      }
 2247      return result;
 2248    }
 2249
 2250    void AddEntry(ZipFile workFile, ZipUpdate update)
 2251    {
 2252      Stream source = null;
 2253
 2254      if (update.Entry.IsFile) {
 2255        source = update.GetSource();
 2256
 2257        if (source == null) {
 2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);
 2259        }
 2260      }
 2261
 2262      if (source != null) {
 2263        using (source) {
 2264          long sourceStreamLength = source.Length;
 2265          if (update.OutEntry.Size < 0) {
 2266            update.OutEntry.Size = sourceStreamLength;
 2267          } else {
 2268            // Check for errant entries.
 2269            if (update.OutEntry.Size != sourceStreamLength) {
 2270              throw new ZipException("Entry size/stream size mismatch");
 2271            }
 2272          }
 2273
 2274          workFile.WriteLocalEntryHeader(update);
 2275
 2276          long dataStart = workFile.baseStream_.Position;
 2277
 2278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2279            CopyBytes(update, output, source, sourceStreamLength, true);
 2280          }
 2281
 2282          long dataEnd = workFile.baseStream_.Position;
 2283          update.OutEntry.CompressedSize = dataEnd - dataStart;
 2284
 2285          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor) {
 2286            var helper = new ZipHelperStream(workFile.baseStream_);
 2287            helper.WriteDataDescriptor(update.OutEntry);
 2288          }
 2289        }
 2290      } else {
 2291        workFile.WriteLocalEntryHeader(update);
 2292        update.OutEntry.CompressedSize = 0;
 2293      }
 2294
 2295    }
 2296
 2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)
 2298    {
 2299      workFile.WriteLocalEntryHeader(update);
 2300      long dataStart = workFile.baseStream_.Position;
 2301
 2302      // TODO: This is slow if the changes don't effect the data!!
 2303      if (update.Entry.IsFile && (update.Filename != null)) {
 2304        using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2305          using (Stream source = this.GetInputStream(update.Entry)) {
 2306            CopyBytes(update, output, source, source.Length, true);
 2307          }
 2308        }
 2309      }
 2310
 2311      long dataEnd = workFile.baseStream_.Position;
 2312      update.Entry.CompressedSize = dataEnd - dataStart;
 2313    }
 2314
 2315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)
 2316    {
 2317      bool skipOver = false || update.Entry.Offset == destinationPosition;
 2318
 2319      if (!skipOver) {
 2320        baseStream_.Position = destinationPosition;
 2321        workFile.WriteLocalEntryHeader(update);
 2322        destinationPosition = baseStream_.Position;
 2323      }
 2324
 2325      long sourcePosition = 0;
 2326
 2327      const int NameLengthOffset = 26;
 2328
 2329      // TODO: Add base for SFX friendly handling
 2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2331
 2332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2333
 2334      // Clumsy way of handling retrieving the original name and extra data length for now.
 2335      // TODO: Stop re-reading name and data length in CopyEntryDirect.
 2336      uint nameLength = ReadLEUshort();
 2337      uint extraLength = ReadLEUshort();
 2338
 2339      sourcePosition = baseStream_.Position + nameLength + extraLength;
 2340
 2341      if (skipOver) {
 2342        if (update.OffsetBasedSize != -1)
 2343          destinationPosition += update.OffsetBasedSize;
 2344        else
 2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar
 2346          // WinZip produces a warning on these entries:
 2347          // "caution: value of lrec.csize (compressed size) changed from ..."
 2348          destinationPosition +=
 2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size
 2350            update.Entry.CompressedSize + GetDescriptorSize(update);
 2351      } else {
 2352        if (update.Entry.CompressedSize > 0) {
 2353          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition);
 2354        }
 2355        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
 2356      }
 2357    }
 2358
 2359    void CopyEntry(ZipFile workFile, ZipUpdate update)
 2360    {
 2361      workFile.WriteLocalEntryHeader(update);
 2362
 2363      if (update.Entry.CompressedSize > 0) {
 2364        const int NameLengthOffset = 26;
 2365
 2366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2367
 2368        // TODO: This wont work for SFX files!
 2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2370
 2371        uint nameLength = ReadLEUshort();
 2372        uint extraLength = ReadLEUshort();
 2373
 2374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);
 2375
 2376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
 2377      }
 2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
 2379    }
 2380
 2381    void Reopen(Stream source)
 2382    {
 2383      if (source == null) {
 2384        throw new ZipException("Failed to reopen archive - no source");
 2385      }
 2386
 2387      isNewArchive_ = false;
 2388      baseStream_ = source;
 2389      ReadEntries();
 2390    }
 2391
 2392    void Reopen()
 2393    {
 2394      if (Name == null) {
 2395        throw new InvalidOperationException("Name is not known cannot Reopen");
 2396      }
 2397
 2398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));
 2399    }
 2400
 2401    void UpdateCommentOnly()
 2402    {
 2403      long baseLength = baseStream_.Length;
 2404
 2405      ZipHelperStream updateFile = null;
 2406
 2407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
 2409        updateFile = new ZipHelperStream(copyStream);
 2410        updateFile.IsStreamOwner = true;
 2411
 2412        baseStream_.Close();
 2413        baseStream_ = null;
 2414      } else {
 2415        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2416          // TODO: archiveStorage wasnt originally intended for this use.
 2417          // Need to revisit this to tidy up handling as archive storage currently doesnt
 2418          // handle the original stream well.
 2419          // The problem is when using an existing zip archive with an in memory archive storage.
 2420          // The open stream wont support writing but the memory storage should open the same file not an in memory one.
 2421
 2422          // Need to tidy up the archive storage interface and contract basically.
 2423          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);
 2424          updateFile = new ZipHelperStream(baseStream_);
 2425        } else {
 2426          baseStream_.Close();
 2427          baseStream_ = null;
 2428          updateFile = new ZipHelperStream(Name);
 2429        }
 2430      }
 2431
 2432      using (updateFile) {
 2433        long locatedCentralDirOffset =
 2434          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2435                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2436        if (locatedCentralDirOffset < 0) {
 2437          throw new ZipException("Cannot find central directory");
 2438        }
 2439
 2440        const int CentralHeaderCommentSizeOffset = 16;
 2441        updateFile.Position += CentralHeaderCommentSizeOffset;
 2442
 2443        byte[] rawComment = newComment_.RawComment;
 2444
 2445        updateFile.WriteLEShort(rawComment.Length);
 2446        updateFile.Write(rawComment, 0, rawComment.Length);
 2447        updateFile.SetLength(updateFile.Position);
 2448      }
 2449
 2450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2452      } else {
 2453        ReadEntries();
 2454      }
 2455    }
 2456
 2457    /// <summary>
 2458    /// Class used to sort updates.
 2459    /// </summary>
 2460    class UpdateComparer : IComparer
 2461    {
 2462      /// <summary>
 2463      /// Compares two objects and returns a value indicating whether one is
 2464      /// less than, equal to or greater than the other.
 2465      /// </summary>
 2466      /// <param name="x">First object to compare</param>
 2467      /// <param name="y">Second object to compare.</param>
 2468      /// <returns>Compare result.</returns>
 2469      public int Compare(
 2470        object x,
 2471        object y)
 2472      {
 2473        var zx = x as ZipUpdate;
 2474        var zy = y as ZipUpdate;
 2475
 2476        int result;
 2477
 2478        if (zx == null) {
 2479          if (zy == null) {
 2480            result = 0;
 2481          } else {
 2482            result = -1;
 2483          }
 2484        } else if (zy == null) {
 2485          result = 1;
 2486        } else {
 2487          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;
 2488          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;
 2489
 2490          result = xCmdValue - yCmdValue;
 2491          if (result == 0) {
 2492            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;
 2493            if (offsetDiff < 0) {
 2494              result = -1;
 2495            } else if (offsetDiff == 0) {
 2496              result = 0;
 2497            } else {
 2498              result = 1;
 2499            }
 2500          }
 2501        }
 2502        return result;
 2503      }
 2504    }
 2505
 2506    void RunUpdates()
 2507    {
 2508      long sizeEntries = 0;
 2509      long endOfStream = 0;
 2510      bool directUpdate = false;
 2511      long destinationPosition = 0; // NOT SFX friendly
 2512
 2513      ZipFile workFile;
 2514
 2515      if (IsNewArchive) {
 2516        workFile = this;
 2517        workFile.baseStream_.Position = 0;
 2518        directUpdate = true;
 2519      } else if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2520        workFile = this;
 2521        workFile.baseStream_.Position = 0;
 2522        directUpdate = true;
 2523
 2524        // Sort the updates by offset within copies/modifies, then adds.
 2525        // This ensures that data required by copies will not be overwritten.
 2526        updates_.Sort(new UpdateComparer());
 2527      } else {
 2528        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
 2529        workFile.UseZip64 = UseZip64;
 2530
 2531        if (key != null) {
 2532          workFile.key = (byte[])key.Clone();
 2533        }
 2534      }
 2535
 2536      try {
 2537        foreach (ZipUpdate update in updates_) {
 2538          if (update != null) {
 2539            switch (update.Command) {
 2540              case UpdateCommand.Copy:
 2541                if (directUpdate) {
 2542                  CopyEntryDirect(workFile, update, ref destinationPosition);
 2543                } else {
 2544                  CopyEntry(workFile, update);
 2545                }
 2546                break;
 2547
 2548              case UpdateCommand.Modify:
 2549                // TODO: Direct modifying of an entry will take some legwork.
 2550                ModifyEntry(workFile, update);
 2551                break;
 2552
 2553              case UpdateCommand.Add:
 2554                if (!IsNewArchive && directUpdate) {
 2555                  workFile.baseStream_.Position = destinationPosition;
 2556                }
 2557
 2558                AddEntry(workFile, update);
 2559
 2560                if (directUpdate) {
 2561                  destinationPosition = workFile.baseStream_.Position;
 2562                }
 2563                break;
 2564            }
 2565          }
 2566        }
 2567
 2568        if (!IsNewArchive && directUpdate) {
 2569          workFile.baseStream_.Position = destinationPosition;
 2570        }
 2571
 2572        long centralDirOffset = workFile.baseStream_.Position;
 2573
 2574        foreach (ZipUpdate update in updates_) {
 2575          if (update != null) {
 2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
 2577          }
 2578        }
 2579
 2580        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 2581        using (ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_)) {
 2582          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);
 2583        }
 2584
 2585        endOfStream = workFile.baseStream_.Position;
 2586
 2587        // And now patch entries...
 2588        foreach (ZipUpdate update in updates_) {
 2589          if (update != null) {
 2590            // If the size of the entry is zero leave the crc as 0 as well.
 2591            // The calculated crc will be all bits on...
 2592            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {
 2593              workFile.baseStream_.Position = update.CrcPatchOffset;
 2594              workFile.WriteLEInt((int)update.OutEntry.Crc);
 2595            }
 2596
 2597            if (update.SizePatchOffset > 0) {
 2598              workFile.baseStream_.Position = update.SizePatchOffset;
 2599              if (update.OutEntry.LocalHeaderRequiresZip64) {
 2600                workFile.WriteLeLong(update.OutEntry.Size);
 2601                workFile.WriteLeLong(update.OutEntry.CompressedSize);
 2602              } else {
 2603                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);
 2604                workFile.WriteLEInt((int)update.OutEntry.Size);
 2605              }
 2606            }
 2607          }
 2608        }
 2609      } catch {
 2610        workFile.Close();
 2611        if (!directUpdate && (workFile.Name != null)) {
 2612          File.Delete(workFile.Name);
 2613        }
 2614        throw;
 2615      }
 2616
 2617      if (directUpdate) {
 2618        workFile.baseStream_.SetLength(endOfStream);
 2619        workFile.baseStream_.Flush();
 2620        isNewArchive_ = false;
 2621        ReadEntries();
 2622      } else {
 2623        baseStream_.Close();
 2624        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2625      }
 2626    }
 2627
 2628    void CheckUpdating()
 2629    {
 2630      if (updates_ == null) {
 2631        throw new InvalidOperationException("BeginUpdate has not been called");
 2632      }
 2633    }
 2634
 2635    #endregion
 2636
 2637    #region ZipUpdate class
 2638    /// <summary>
 2639    /// Represents a pending update to a Zip file.
 2640    /// </summary>
 2641    class ZipUpdate
 2642    {
 2643      #region Constructors
 2644      public ZipUpdate(string fileName, ZipEntry entry)
 2645      {
 2646        command_ = UpdateCommand.Add;
 2647        entry_ = entry;
 2648        filename_ = fileName;
 2649      }
 2650
 2651      [Obsolete]
 2652      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 2653      {
 2654        command_ = UpdateCommand.Add;
 2655        entry_ = new ZipEntry(entryName);
 2656        entry_.CompressionMethod = compressionMethod;
 2657        filename_ = fileName;
 2658      }
 2659
 2660      [Obsolete]
 2661      public ZipUpdate(string fileName, string entryName)
 2662        : this(fileName, entryName, CompressionMethod.Deflated)
 2663      {
 2664        // Do nothing.
 2665      }
 2666
 2667      [Obsolete]
 2668      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 2669      {
 2670        command_ = UpdateCommand.Add;
 2671        entry_ = new ZipEntry(entryName);
 2672        entry_.CompressionMethod = compressionMethod;
 2673        dataSource_ = dataSource;
 2674      }
 2675
 2676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 2677      {
 2678        command_ = UpdateCommand.Add;
 2679        entry_ = entry;
 2680        dataSource_ = dataSource;
 2681      }
 2682
 2683      public ZipUpdate(ZipEntry original, ZipEntry updated)
 2684      {
 2685        throw new ZipException("Modify not currently supported");
 2686        /*
 2687          command_ = UpdateCommand.Modify;
 2688          entry_ = ( ZipEntry )original.Clone();
 2689          outEntry_ = ( ZipEntry )updated.Clone();
 2690        */
 2691      }
 2692
 2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)
 2694      {
 2695        command_ = command;
 2696        entry_ = (ZipEntry)entry.Clone();
 2697      }
 2698
 2699
 2700      /// <summary>
 2701      /// Copy an existing entry.
 2702      /// </summary>
 2703      /// <param name="entry">The existing entry to copy.</param>
 2704      public ZipUpdate(ZipEntry entry)
 2705        : this(UpdateCommand.Copy, entry)
 2706      {
 2707        // Do nothing.
 2708      }
 2709      #endregion
 2710
 2711      /// <summary>
 2712      /// Get the <see cref="ZipEntry"/> for this update.
 2713      /// </summary>
 2714      /// <remarks>This is the source or original entry.</remarks>
 2715      public ZipEntry Entry {
 2716        get { return entry_; }
 2717      }
 2718
 2719      /// <summary>
 2720      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.
 2721      /// </summary>
 2722      public ZipEntry OutEntry {
 2723        get {
 2724          if (outEntry_ == null) {
 2725            outEntry_ = (ZipEntry)entry_.Clone();
 2726          }
 2727
 2728          return outEntry_;
 2729        }
 2730      }
 2731
 2732      /// <summary>
 2733      /// Get the command for this update.
 2734      /// </summary>
 2735      public UpdateCommand Command {
 2736        get { return command_; }
 2737      }
 2738
 2739      /// <summary>
 2740      /// Get the filename if any for this update.  Null if none exists.
 2741      /// </summary>
 2742      public string Filename {
 2743        get { return filename_; }
 2744      }
 2745
 2746      /// <summary>
 2747      /// Get/set the location of the size patch for this update.
 2748      /// </summary>
 2749      public long SizePatchOffset {
 2750        get { return sizePatchOffset_; }
 2751        set { sizePatchOffset_ = value; }
 2752      }
 2753
 2754      /// <summary>
 2755      /// Get /set the location of the crc patch for this update.
 2756      /// </summary>
 2757      public long CrcPatchOffset {
 2758        get { return crcPatchOffset_; }
 2759        set { crcPatchOffset_ = value; }
 2760      }
 2761
 2762      /// <summary>
 2763      /// Get/set the size calculated by offset.
 2764      /// Specifically, the difference between this and next entry's starting offset.
 2765      /// </summary>
 2766      public long OffsetBasedSize {
 2767        get { return _offsetBasedSize; }
 2768        set { _offsetBasedSize = value; }
 2769      }
 2770
 2771      public Stream GetSource()
 2772      {
 2773        Stream result = null;
 2774        if (dataSource_ != null) {
 2775          result = dataSource_.GetSource();
 2776        }
 2777
 2778        return result;
 2779      }
 2780
 2781      #region Instance Fields
 2782      ZipEntry entry_;
 2783      ZipEntry outEntry_;
 2784      UpdateCommand command_;
 2785      IStaticDataSource dataSource_;
 2786      string filename_;
 2787      long sizePatchOffset_ = -1;
 2788      long crcPatchOffset_ = -1;
 2789      long _offsetBasedSize = -1;
 2790      #endregion
 2791    }
 2792
 2793    #endregion
 2794    #endregion
 2795
 2796    #region Disposing
 2797
 2798    #region IDisposable Members
 2799    void IDisposable.Dispose()
 2800    {
 2801      Close();
 2802    }
 2803    #endregion
 2804
 2805    void DisposeInternal(bool disposing)
 2806    {
 2807      if (!isDisposed_) {
 2808        isDisposed_ = true;
 2809        entries_ = new ZipEntry[0];
 2810
 2811        if (IsStreamOwner && (baseStream_ != null)) {
 2812          lock (baseStream_) {
 2813            baseStream_.Close();
 2814          }
 2815        }
 2816
 2817        PostUpdateCleanup();
 2818      }
 2819    }
 2820
 2821    /// <summary>
 2822    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.
 2823    /// </summary>
 2824    /// <param name="disposing">true to release both managed and unmanaged resources;
 2825    /// false to release only unmanaged resources.</param>
 2826    protected virtual void Dispose(bool disposing)
 2827    {
 2828      DisposeInternal(disposing);
 2829    }
 2830
 2831    #endregion
 2832
 2833    #region Internal routines
 2834    #region Reading
 2835    /// <summary>
 2836    /// Read an unsigned short in little endian byte order.
 2837    /// </summary>
 2838    /// <returns>Returns the value read.</returns>
 2839    /// <exception cref="EndOfStreamException">
 2840    /// The stream ends prematurely
 2841    /// </exception>
 2842    ushort ReadLEUshort()
 2843    {
 2844      int data1 = baseStream_.ReadByte();
 2845
 2846      if (data1 < 0) {
 2847        throw new EndOfStreamException("End of stream");
 2848      }
 2849
 2850      int data2 = baseStream_.ReadByte();
 2851
 2852      if (data2 < 0) {
 2853        throw new EndOfStreamException("End of stream");
 2854      }
 2855
 2856
 2857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));
 2858    }
 2859
 2860    /// <summary>
 2861    /// Read a uint in little endian byte order.
 2862    /// </summary>
 2863    /// <returns>Returns the value read.</returns>
 2864    /// <exception cref="IOException">
 2865    /// An i/o error occurs.
 2866    /// </exception>
 2867    /// <exception cref="System.IO.EndOfStreamException">
 2868    /// The file ends prematurely
 2869    /// </exception>
 2870    uint ReadLEUint()
 2871    {
 2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));
 2873    }
 2874
 2875    ulong ReadLEUlong()
 2876    {
 2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);
 2878    }
 2879
 2880    #endregion
 2881    // NOTE this returns the offset of the first byte after the signature.
 2882    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 2883    {
 2884      using (ZipHelperStream les = new ZipHelperStream(baseStream_)) {
 2885        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
 2886      }
 2887    }
 2888
 2889    /// <summary>
 2890    /// Search for and read the central directory of a zip file filling the entries array.
 2891    /// </summary>
 2892    /// <exception cref="System.IO.IOException">
 2893    /// An i/o error occurs.
 2894    /// </exception>
 2895    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 2896    /// The central directory is malformed or cannot be found
 2897    /// </exception>
 2898    void ReadEntries()
 2899    {
 2900      // Search for the End Of Central Directory.  When a zip comment is
 2901      // present the directory will start earlier
 2902      //
 2903      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
 2904      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
 2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
 2906      // this could be invalid.
 2907      // Could also speed this up by reading memory in larger blocks.
 2908
 2909      if (baseStream_.CanSeek == false) {
 2910        throw new ZipException("ZipFile stream must be seekable");
 2911      }
 2912
 2913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2915
 2916      if (locatedEndOfCentralDir < 0) {
 2917        throw new ZipException("Cannot find central directory");
 2918      }
 2919
 2920      // Read end of central directory record
 2921      ushort thisDiskNumber = ReadLEUshort();
 2922      ushort startCentralDirDisk = ReadLEUshort();
 2923      ulong entriesForThisDisk = ReadLEUshort();
 2924      ulong entriesForWholeCentralDir = ReadLEUshort();
 2925      ulong centralDirSize = ReadLEUint();
 2926      long offsetOfCentralDir = ReadLEUint();
 2927      uint commentSize = ReadLEUshort();
 2928
 2929      if (commentSize > 0) {
 2930        byte[] comment = new byte[commentSize];
 2931
 2932        StreamUtils.ReadFully(baseStream_, comment);
 2933        comment_ = ZipConstants.ConvertToString(comment);
 2934      } else {
 2935        comment_ = string.Empty;
 2936      }
 2937
 2938      bool isZip64 = false;
 2939
 2940      // Check if zip64 header information is required.
 2941      if ((thisDiskNumber == 0xffff) ||
 2942        (startCentralDirDisk == 0xffff) ||
 2943        (entriesForThisDisk == 0xffff) ||
 2944        (entriesForWholeCentralDir == 0xffff) ||
 2945        (centralDirSize == 0xffffffff) ||
 2946        (offsetOfCentralDir == 0xffffffff)) {
 2947        isZip64 = true;
 2948
 2949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 
 2950        if (offset < 0) {
 2951          throw new ZipException("Cannot find Zip64 locator");
 2952        }
 2953
 2954        // number of the disk with the start of the zip64 end of central directory 4 bytes
 2955        // relative offset of the zip64 end of central directory record 8 bytes
 2956        // total number of disks 4 bytes
 2957        ReadLEUint(); // startDisk64 is not currently used
 2958        ulong offset64 = ReadLEUlong();
 2959        uint totalDisks = ReadLEUint();
 2960
 2961        baseStream_.Position = (long)offset64;
 2962        long sig64 = ReadLEUint();
 2963
 2964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {
 2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
 2966        }
 2967
 2968        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
 2969        ulong recordSize = ReadLEUlong();
 2970        int versionMadeBy = ReadLEUshort();
 2971        int versionToExtract = ReadLEUshort();
 2972        uint thisDisk = ReadLEUint();
 2973        uint centralDirDisk = ReadLEUint();
 2974        entriesForThisDisk = ReadLEUlong();
 2975        entriesForWholeCentralDir = ReadLEUlong();
 2976        centralDirSize = ReadLEUlong();
 2977        offsetOfCentralDir = (long)ReadLEUlong();
 2978
 2979        // NOTE: zip64 extensible data sector (variable size) is ignored.
 2980      }
 2981
 2982      entries_ = new ZipEntry[entriesForThisDisk];
 2983
 2984      // SFX/embedded support, find the offset of the first entry vis the start of the stream
 2985      // This applies to Zip files that are appended to the end of an SFX stub.
 2986      // Or are appended as a resource to an executable.
 2987      // Zip files created by some archivers have the offsets altered to reflect the true offsets
 2988      // and so dont require any adjustment here...
 2989      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
 2990      if (!isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize))) {
 2991        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
 2992        if (offsetOfFirstEntry <= 0) {
 2993          throw new ZipException("Invalid embedded zip archive");
 2994        }
 2995      }
 2996
 2997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
 2998
 2999      for (ulong i = 0; i < entriesForThisDisk; i++) {
 3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
 3001          throw new ZipException("Wrong Central Directory signature");
 3002        }
 3003
 3004        int versionMadeBy = ReadLEUshort();
 3005        int versionToExtract = ReadLEUshort();
 3006        int bitFlags = ReadLEUshort();
 3007        int method = ReadLEUshort();
 3008        uint dostime = ReadLEUint();
 3009        uint crc = ReadLEUint();
 3010        var csize = (long)ReadLEUint();
 3011        var size = (long)ReadLEUint();
 3012        int nameLen = ReadLEUshort();
 3013        int extraLen = ReadLEUshort();
 3014        int commentLen = ReadLEUshort();
 3015
 3016        int diskStartNo = ReadLEUshort();  // Not currently used
 3017        int internalAttributes = ReadLEUshort();  // Not currently used
 3018
 3019        uint externalAttributes = ReadLEUint();
 3020        long offset = ReadLEUint();
 3021
 3022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
 3023
 3024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
 3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);
 3026
 3027        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
 3028        entry.Crc = crc & 0xffffffffL;
 3029        entry.Size = size & 0xffffffffL;
 3030        entry.CompressedSize = csize & 0xffffffffL;
 3031        entry.Flags = bitFlags;
 3032        entry.DosTime = (uint)dostime;
 3033        entry.ZipFileIndex = (long)i;
 3034        entry.Offset = offset;
 3035        entry.ExternalFileAttributes = (int)externalAttributes;
 3036
 3037        if ((bitFlags & 8) == 0) {
 3038          entry.CryptoCheckValue = (byte)(crc >> 24);
 3039        } else {
 3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
 3041        }
 3042
 3043        if (extraLen > 0) {
 3044          byte[] extra = new byte[extraLen];
 3045          StreamUtils.ReadFully(baseStream_, extra);
 3046          entry.ExtraData = extra;
 3047        }
 3048
 3049        entry.ProcessExtraData(false);
 3050
 3051        if (commentLen > 0) {
 3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
 3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
 3054        }
 3055
 3056        entries_[i] = entry;
 3057      }
 3058    }
 3059
 3060    /// <summary>
 3061    /// Locate the data for a given entry.
 3062    /// </summary>
 3063    /// <returns>
 3064    /// The start offset of the data.
 3065    /// </returns>
 3066    /// <exception cref="System.IO.EndOfStreamException">
 3067    /// The stream ends prematurely
 3068    /// </exception>
 3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 3070    /// The local header signature is invalid, the entry and central header file name lengths are different
 3071    /// or the local and entry compression methods dont match
 3072    /// </exception>
 3073    long LocateEntry(ZipEntry entry)
 3074    {
 3075      return TestLocalHeader(entry, HeaderTest.Extract);
 3076    }
 3077
 3078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
 3079    {
 3080      CryptoStream result = null;
 3081
 3082      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3084        var classicManaged = new PkzipClassicManaged();
 3085
 3086        OnKeysRequired(entry.Name);
 3087        if (HaveKeys == false) {
 3088          throw new ZipException("No password available for encrypted stream");
 3089        }
 3090
 3091        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
 3092        CheckClassicPassword(result, entry);
 3093      } else {
 3094        if (entry.Version == ZipConstants.VERSION_AES) {
 3095          //
 3096          OnKeysRequired(entry.Name);
 3097          if (HaveKeys == false) {
 3098            throw new ZipException("No password available for AES encrypted stream");
 3099          }
 3100          int saltLen = entry.AESSaltLen;
 3101          byte[] saltBytes = new byte[saltLen];
 3102          int saltIn = baseStream.Read(saltBytes, 0, saltLen);
 3103          if (saltIn != saltLen)
 3104            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
 3105          //
 3106          byte[] pwdVerifyRead = new byte[2];
 3107          baseStream.Read(pwdVerifyRead, 0, 2);
 3108          int blockSize = entry.AESKeySize / 8;   // bits to bytes
 3109
 3110          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
 3111          byte[] pwdVerifyCalc = decryptor.PwdVerifier;
 3112          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
 3113            throw new ZipException("Invalid password for AES");
 3114          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
 3115        } else {
 3116          throw new ZipException("Decryption method not supported");
 3117        }
 3118      }
 3119
 3120      return result;
 3121    }
 3122
 3123    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
 3124    {
 3125      CryptoStream result = null;
 3126      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3127        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3128        var classicManaged = new PkzipClassicManaged();
 3129
 3130        OnKeysRequired(entry.Name);
 3131        if (HaveKeys == false) {
 3132          throw new ZipException("No password available for encrypted stream");
 3133        }
 3134
 3135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
 3136        // which doesnt do this.
 3137        result = new CryptoStream(new UncompressedStream(baseStream),
 3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
 3139
 3140        if ((entry.Crc < 0) || (entry.Flags & 8) != 0) {
 3141          WriteEncryptionHeader(result, entry.DosTime << 16);
 3142        } else {
 3143          WriteEncryptionHeader(result, entry.Crc);
 3144        }
 3145      }
 3146      return result;
 3147    }
 3148
 3149    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
 3150    {
 3151      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
 3152      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
 3153      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
 3154        throw new ZipException("Invalid password");
 3155      }
 3156    }
 3157
 3158    static void WriteEncryptionHeader(Stream stream, long crcValue)
 3159    {
 3160      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
 3161      var rnd = new Random();
 3162      rnd.NextBytes(cryptBuffer);
 3163      cryptBuffer[11] = (byte)(crcValue >> 24);
 3164      stream.Write(cryptBuffer, 0, cryptBuffer.Length);
 3165    }
 3166
 3167    #endregion
 3168
 3169    #region Instance Fields
 3170    bool isDisposed_;
 3171    string name_;
 3172    string comment_;
 3173    string rawPassword_;
 3174    Stream baseStream_;
 3175    bool isStreamOwner;
 3176    long offsetOfFirstEntry;
 3177    ZipEntry[] entries_;
 3178    byte[] key;
 3179    bool isNewArchive_;
 3180
 3181    // Default is dynamic which is not backwards compatible and can cause problems
 3182    // with XP's built in compression which cant read Zip64 archives.
 3183    // However it does avoid the situation were a large file is added and cannot be completed correctly.
 3184    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.
 3185    UseZip64 useZip64_ = UseZip64.Dynamic;
 3186
 3187    #region Zip Update Instance Fields
 3188    ArrayList updates_;
 3189    long updateCount_; // Count is managed manually as updates_ can contain nulls!
 3190    Hashtable updateIndex_;
 3191    IArchiveStorage archiveStorage_;
 3192    IDynamicDataSource updateDataSource_;
 3193    bool contentsEdited_;
 3194    int bufferSize_ = DefaultBufferSize;
 3195    byte[] copyBuffer_;
 3196    ZipString newComment_;
 3197    bool commentEdited_;
 3198    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();
 3199    #endregion
 3200    #endregion
 3201
 3202    #region Support Classes
 3203    /// <summary>
 3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.
 3205    /// </summary>
 3206    class ZipString
 3207    {
 3208      #region Constructors
 3209      /// <summary>
 3210      /// Initialise a <see cref="ZipString"/> with a string.
 3211      /// </summary>
 3212      /// <param name="comment">The textual string form.</param>
 3213      public ZipString(string comment)
 3214      {
 3215        comment_ = comment;
 3216        isSourceString_ = true;
 3217      }
 3218
 3219      /// <summary>
 3220      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.
 3221      /// </summary>
 3222      /// <param name="rawString"></param>
 3223      public ZipString(byte[] rawString)
 3224      {
 3225        rawComment_ = rawString;
 3226      }
 3227      #endregion
 3228
 3229      /// <summary>
 3230      /// Get a value indicating the original source of data for this instance.
 3231      /// True if the source was a string; false if the source was binary data.
 3232      /// </summary>
 3233      public bool IsSourceString {
 3234        get { return isSourceString_; }
 3235      }
 3236
 3237      /// <summary>
 3238      /// Get the length of the comment when represented as raw bytes.
 3239      /// </summary>
 3240      public int RawLength {
 3241        get {
 3242          MakeBytesAvailable();
 3243          return rawComment_.Length;
 3244        }
 3245      }
 3246
 3247      /// <summary>
 3248      /// Get the comment in its 'raw' form as plain bytes.
 3249      /// </summary>
 3250      public byte[] RawComment {
 3251        get {
 3252          MakeBytesAvailable();
 3253          return (byte[])rawComment_.Clone();
 3254        }
 3255      }
 3256
 3257      /// <summary>
 3258      /// Reset the comment to its initial state.
 3259      /// </summary>
 3260      public void Reset()
 3261      {
 3262        if (isSourceString_) {
 3263          rawComment_ = null;
 3264        } else {
 3265          comment_ = null;
 3266        }
 3267      }
 3268
 3269      void MakeTextAvailable()
 3270      {
 3271        if (comment_ == null) {
 3272          comment_ = ZipConstants.ConvertToString(rawComment_);
 3273        }
 3274      }
 3275
 3276      void MakeBytesAvailable()
 3277      {
 3278        if (rawComment_ == null) {
 3279          rawComment_ = ZipConstants.ConvertToArray(comment_);
 3280        }
 3281      }
 3282
 3283      /// <summary>
 3284      /// Implicit conversion of comment to a string.
 3285      /// </summary>
 3286      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>
 3287      /// <returns>The textual equivalent for the input value.</returns>
 3288      static public implicit operator string(ZipString zipString)
 3289      {
 3290        zipString.MakeTextAvailable();
 3291        return zipString.comment_;
 3292      }
 3293
 3294      #region Instance Fields
 3295      string comment_;
 3296      byte[] rawComment_;
 3297      bool isSourceString_;
 3298      #endregion
 3299    }
 3300
 3301    /// <summary>
 3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>
 3303    /// </summary>
 3304    class ZipEntryEnumerator : IEnumerator
 3305    {
 3306      #region Constructors
 3307      public ZipEntryEnumerator(ZipEntry[] entries)
 3308      {
 3309        array = entries;
 3310      }
 3311
 3312      #endregion
 3313      #region IEnumerator Members
 3314      public object Current {
 3315        get {
 3316          return array[index];
 3317        }
 3318      }
 3319
 3320      public void Reset()
 3321      {
 3322        index = -1;
 3323      }
 3324
 3325      public bool MoveNext()
 3326      {
 3327        return (++index < array.Length);
 3328      }
 3329      #endregion
 3330      #region Instance Fields
 3331      ZipEntry[] array;
 3332      int index = -1;
 3333      #endregion
 3334    }
 3335
 3336    /// <summary>
 3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data
 3338    /// to and flush, but cannot read, seek or do anything else to.
 3339    /// </summary>
 3340    class UncompressedStream : Stream
 3341    {
 3342      #region Constructors
 3343      public UncompressedStream(Stream baseStream)
 3344      {
 3345        baseStream_ = baseStream;
 3346      }
 3347
 3348      #endregion
 3349
 3350      /// <summary>
 3351      /// Close this stream instance.
 3352      /// </summary>
 3353      public override void Close()
 3354      {
 3355        // Do nothing
 3356      }
 3357
 3358      /// <summary>
 3359      /// Gets a value indicating whether the current stream supports reading.
 3360      /// </summary>
 3361      public override bool CanRead {
 3362        get {
 3363          return false;
 3364        }
 3365      }
 3366
 3367      /// <summary>
 3368      /// Write any buffered data to underlying storage.
 3369      /// </summary>
 3370      public override void Flush()
 3371      {
 3372        baseStream_.Flush();
 3373      }
 3374
 3375      /// <summary>
 3376      /// Gets a value indicating whether the current stream supports writing.
 3377      /// </summary>
 3378      public override bool CanWrite {
 3379        get {
 3380          return baseStream_.CanWrite;
 3381        }
 3382      }
 3383
 3384      /// <summary>
 3385      /// Gets a value indicating whether the current stream supports seeking.
 3386      /// </summary>
 3387      public override bool CanSeek {
 3388        get {
 3389          return false;
 3390        }
 3391      }
 3392
 3393      /// <summary>
 3394      /// Get the length in bytes of the stream.
 3395      /// </summary>
 3396      public override long Length {
 3397        get {
 3398          return 0;
 3399        }
 3400      }
 3401
 3402      /// <summary>
 3403      /// Gets or sets the position within the current stream.
 3404      /// </summary>
 3405      public override long Position {
 3406        get {
 3407          return baseStream_.Position;
 3408        }
 3409        set {
 3410          throw new NotImplementedException();
 3411        }
 3412      }
 3413
 3414      /// <summary>
 3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3416      /// </summary>
 3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3419      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3420      /// <returns>
 3421      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3422      /// </returns>
 3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3425      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3426      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3427      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3428      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3429      public override int Read(byte[] buffer, int offset, int count)
 3430      {
 3431        return 0;
 3432      }
 3433
 3434      /// <summary>
 3435      /// Sets the position within the current stream.
 3436      /// </summary>
 3437      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3438      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3439      /// <returns>
 3440      /// The new position within the current stream.
 3441      /// </returns>
 3442      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3443      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3445      public override long Seek(long offset, SeekOrigin origin)
 3446      {
 3447        return 0;
 3448      }
 3449
 3450      /// <summary>
 3451      /// Sets the length of the current stream.
 3452      /// </summary>
 3453      /// <param name="value">The desired length of the current stream in bytes.</param>
 3454      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3455      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3456      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3457      public override void SetLength(long value)
 3458      {
 3459      }
 3460
 3461      /// <summary>
 3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3463      /// </summary>
 3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3466      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3467      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3468      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3469      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3470      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3471      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3472      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3473      public override void Write(byte[] buffer, int offset, int count)
 3474      {
 3475        baseStream_.Write(buffer, offset, count);
 3476      }
 3477
 3478      readonly
 3479
 3480      #region Instance Fields
 3481      Stream baseStream_;
 3482      #endregion
 3483    }
 3484
 3485    /// <summary>
 3486    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>
 3487    /// whose data is only a part or subsection of a file.
 3488    /// </summary>
 3489    class PartialInputStream : Stream
 3490    {
 3491      #region Constructors
 3492      /// <summary>
 3493      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.
 3494      /// </summary>
 3495      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>
 3496      /// <param name="start">The start of the partial data.</param>
 3497      /// <param name="length">The length of the partial data.</param>
 3498      public PartialInputStream(ZipFile zipFile, long start, long length)
 3499      {
 3500        start_ = start;
 3501        length_ = length;
 3502
 3503        // Although this is the only time the zipfile is used
 3504        // keeping a reference here prevents premature closure of
 3505        // this zip file and thus the baseStream_.
 3506
 3507        // Code like this will cause apparently random failures depending
 3508        // on the size of the files and when garbage is collected.
 3509        //
 3510        // ZipFile z = new ZipFile (stream);
 3511        // Stream reader = z.GetInputStream(0);
 3512        // uses reader here....
 3513        zipFile_ = zipFile;
 3514        baseStream_ = zipFile_.baseStream_;
 3515        readPos_ = start;
 3516        end_ = start + length;
 3517      }
 3518      #endregion
 3519
 3520      /// <summary>
 3521      /// Read a byte from this stream.
 3522      /// </summary>
 3523      /// <returns>Returns the byte read or -1 on end of stream.</returns>
 3524      public override int ReadByte()
 3525      {
 3526        if (readPos_ >= end_) {
 3527          // -1 is the correct value at end of stream.
 3528          return -1;
 3529        }
 3530
 3531        lock (baseStream_) {
 3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);
 3533          return baseStream_.ReadByte();
 3534        }
 3535      }
 3536
 3537      /// <summary>
 3538      /// Close this <see cref="PartialInputStream">partial input stream</see>.
 3539      /// </summary>
 3540      /// <remarks>
 3541      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.
 3542      /// </remarks>
 3543      public override void Close()
 3544      {
 3545        // Do nothing at all!
 3546      }
 3547
 3548      /// <summary>
 3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3550      /// </summary>
 3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3553      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3554      /// <returns>
 3555      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3556      /// </returns>
 3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3559      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3560      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3561      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3562      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3563      public override int Read(byte[] buffer, int offset, int count)
 3564      {
 3565        lock (baseStream_) {
 3566          if (count > end_ - readPos_) {
 3567            count = (int)(end_ - readPos_);
 3568            if (count == 0) {
 3569              return 0;
 3570            }
 3571          }
 3572          // Protect against Stream implementations that throw away their buffer on every Seek
 3573          // (for example, Mono FileStream)
 3574          if (baseStream_.Position != readPos_) {
 3575            baseStream_.Seek(readPos_, SeekOrigin.Begin);
 3576          }
 3577          int readCount = baseStream_.Read(buffer, offset, count);
 3578          if (readCount > 0) {
 3579            readPos_ += readCount;
 3580          }
 3581          return readCount;
 3582        }
 3583      }
 3584
 3585      /// <summary>
 3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3587      /// </summary>
 3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3590      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3591      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3592      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3593      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3594      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3595      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3596      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3597      public override void Write(byte[] buffer, int offset, int count)
 3598      {
 3599        throw new NotSupportedException();
 3600      }
 3601
 3602      /// <summary>
 3603      /// When overridden in a derived class, sets the length of the current stream.
 3604      /// </summary>
 3605      /// <param name="value">The desired length of the current stream in bytes.</param>
 3606      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3607      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3608      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3609      public override void SetLength(long value)
 3610      {
 3611        throw new NotSupportedException();
 3612      }
 3613
 3614      /// <summary>
 3615      /// When overridden in a derived class, sets the position within the current stream.
 3616      /// </summary>
 3617      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3618      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3619      /// <returns>
 3620      /// The new position within the current stream.
 3621      /// </returns>
 3622      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3623      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3625      public override long Seek(long offset, SeekOrigin origin)
 3626      {
 3627        long newPos = readPos_;
 3628
 3629        switch (origin) {
 3630          case SeekOrigin.Begin:
 3631            newPos = start_ + offset;
 3632            break;
 3633
 3634          case SeekOrigin.Current:
 3635            newPos = readPos_ + offset;
 3636            break;
 3637
 3638          case SeekOrigin.End:
 3639            newPos = end_ + offset;
 3640            break;
 3641        }
 3642
 3643        if (newPos < start_) {
 3644          throw new ArgumentException("Negative position is invalid");
 3645        }
 3646
 3647        if (newPos >= end_) {
 3648          throw new IOException("Cannot seek past end");
 3649        }
 3650        readPos_ = newPos;
 3651        return readPos_;
 3652      }
 3653
 3654      /// <summary>
 3655      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
 3656      /// </summary>
 3657      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3658      public override void Flush()
 3659      {
 3660        // Nothing to do.
 3661      }
 3662
 3663      /// <summary>
 3664      /// Gets or sets the position within the current stream.
 3665      /// </summary>
 3666      /// <value></value>
 3667      /// <returns>The current position within the stream.</returns>
 3668      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3669      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>
 3670      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3671      public override long Position {
 3672        get { return readPos_ - start_; }
 3673        set {
 3674          long newPos = start_ + value;
 3675
 3676          if (newPos < start_) {
 3677            throw new ArgumentException("Negative position is invalid");
 3678          }
 3679
 3680          if (newPos >= end_) {
 3681            throw new InvalidOperationException("Cannot seek past end");
 3682          }
 3683          readPos_ = newPos;
 3684        }
 3685      }
 3686
 3687      /// <summary>
 3688      /// Gets the length in bytes of the stream.
 3689      /// </summary>
 3690      /// <value></value>
 3691      /// <returns>A long value representing the length of the stream in bytes.</returns>
 3692      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep
 3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3694      public override long Length {
 3695        get { return length_; }
 3696      }
 3697
 3698      /// <summary>
 3699      /// Gets a value indicating whether the current stream supports writing.
 3700      /// </summary>
 3701      /// <value>false</value>
 3702      /// <returns>true if the stream supports writing; otherwise, false.</returns>
 3703      public override bool CanWrite {
 3704        get { return false; }
 3705      }
 3706
 3707      /// <summary>
 3708      /// Gets a value indicating whether the current stream supports seeking.
 3709      /// </summary>
 3710      /// <value>true</value>
 3711      /// <returns>true if the stream supports seeking; otherwise, false.</returns>
 3712      public override bool CanSeek {
 3713        get { return true; }
 3714      }
 3715
 3716      /// <summary>
 3717      /// Gets a value indicating whether the current stream supports reading.
 3718      /// </summary>
 3719      /// <value>true.</value>
 3720      /// <returns>true if the stream supports reading; otherwise, false.</returns>
 3721      public override bool CanRead {
 3722        get { return true; }
 3723      }
 3724
 3725      /// <summary>
 3726      /// Gets a value that determines whether the current stream can time out.
 3727      /// </summary>
 3728      /// <value></value>
 3729      /// <returns>A value that determines whether the current stream can time out.</returns>
 3730      public override bool CanTimeout {
 3731        get { return baseStream_.CanTimeout; }
 3732      }
 3733      #region Instance Fields
 3734      ZipFile zipFile_;
 3735      Stream baseStream_;
 3736      long start_;
 3737      long length_;
 3738      long readPos_;
 3739      long end_;
 3740      #endregion
 3741    }
 3742    #endregion
 3743  }
 3744
 3745  #endregion
 3746
 3747  #region DataSources
 3748  /// <summary>
 3749  /// Provides a static way to obtain a source of data for an entry.
 3750  /// </summary>
 3751  public interface IStaticDataSource
 3752  {
 3753    /// <summary>
 3754    /// Get a source of data by creating a new stream.
 3755    /// </summary>
 3756    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3757    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3758    Stream GetSource();
 3759  }
 3760
 3761  /// <summary>
 3762  /// Represents a source of data that can dynamically provide
 3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.
 3764  /// </summary>
 3765  public interface IDynamicDataSource
 3766  {
 3767    /// <summary>
 3768    /// Get a data source.
 3769    /// </summary>
 3770    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>
 3771    /// <param name="name">The name for data if known.</param>
 3772    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3773    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3774    Stream GetSource(ZipEntry entry, string name);
 3775  }
 3776
 3777  /// <summary>
 3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.
 3779  /// </summary>
 3780  public class StaticDiskDataSource : IStaticDataSource
 3781  {
 3782    /// <summary>
 3783    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>
 3784    /// </summary>
 3785    /// <param name="fileName">The name of the file to obtain data from.</param>
 3786    public StaticDiskDataSource(string fileName)
 3787    {
 3788      fileName_ = fileName;
 3789    }
 3790
 3791    #region IDataSource Members
 3792
 3793    /// <summary>
 3794    /// Get a <see cref="Stream"/> providing data.
 3795    /// </summary>
 3796    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>
 3797    public Stream GetSource()
 3798    {
 3799      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 3800    }
 3801
 3802    readonly
 3803
 3804    #endregion
 3805    #region Instance Fields
 3806    string fileName_;
 3807    #endregion
 3808  }
 3809
 3810
 3811  /// <summary>
 3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.
 3813  /// </summary>
 3814  public class DynamicDiskDataSource : IDynamicDataSource
 3815  {
 3816
 3817    #region IDataSource Members
 3818    /// <summary>
 3819    /// Get a <see cref="Stream"/> providing data for an entry.
 3820    /// </summary>
 3821    /// <param name="entry">The entry to provide data for.</param>
 3822    /// <param name="name">The file name for data if known.</param>
 3823    /// <returns>Returns a stream providing data; or null if not available</returns>
 3824    public Stream GetSource(ZipEntry entry, string name)
 3825    {
 3826      Stream result = null;
 3827
 3828      if (name != null) {
 3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 3830      }
 3831
 3832      return result;
 3833    }
 3834
 3835    #endregion
 3836  }
 3837
 3838  #endregion
 3839
 3840  #region Archive Storage
 3841  /// <summary>
 3842  /// Defines facilities for data storage when updating Zip Archives.
 3843  /// </summary>
 3844  public interface IArchiveStorage
 3845  {
 3846    /// <summary>
 3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.
 3848    /// </summary>
 3849    FileUpdateMode UpdateMode { get; }
 3850
 3851    /// <summary>
 3852    /// Get an empty <see cref="Stream"/> that can be used for temporary output.
 3853    /// </summary>
 3854    /// <returns>Returns a temporary output <see cref="Stream"/></returns>
 3855    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3856    Stream GetTemporaryOutput();
 3857
 3858    /// <summary>
 3859    /// Convert a temporary output stream to a final stream.
 3860    /// </summary>
 3861    /// <returns>The resulting final <see cref="Stream"/></returns>
 3862    /// <seealso cref="GetTemporaryOutput"/>
 3863    Stream ConvertTemporaryToFinal();
 3864
 3865    /// <summary>
 3866    /// Make a temporary copy of the original stream.
 3867    /// </summary>
 3868    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 3869    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3870    Stream MakeTemporaryCopy(Stream stream);
 3871
 3872    /// <summary>
 3873    /// Return a stream suitable for performing direct updates on the original source.
 3874    /// </summary>
 3875    /// <param name="stream">The current stream.</param>
 3876    /// <returns>Returns a stream suitable for direct updating.</returns>
 3877    /// <remarks>This may be the current stream passed.</remarks>
 3878    Stream OpenForDirectUpdate(Stream stream);
 3879
 3880    /// <summary>
 3881    /// Dispose of this instance.
 3882    /// </summary>
 3883    void Dispose();
 3884  }
 3885
 3886  /// <summary>
 3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.
 3888  /// </summary>
 3889  abstract public class BaseArchiveStorage : IArchiveStorage
 3890  {
 3891    #region Constructors
 3892    /// <summary>
 3893    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.
 3894    /// </summary>
 3895    /// <param name="updateMode">The update mode.</param>
 3896    protected BaseArchiveStorage(FileUpdateMode updateMode)
 3897    {
 3898      updateMode_ = updateMode;
 3899    }
 3900    #endregion
 3901
 3902    #region IArchiveStorage Members
 3903
 3904    /// <summary>
 3905    /// Gets a temporary output <see cref="Stream"/>
 3906    /// </summary>
 3907    /// <returns>Returns the temporary output stream.</returns>
 3908    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3909    public abstract Stream GetTemporaryOutput();
 3910
 3911    /// <summary>
 3912    /// Converts the temporary <see cref="Stream"/> to its final form.
 3913    /// </summary>
 3914    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 3915    /// the final storage for the archive.</returns>
 3916    /// <seealso cref="GetTemporaryOutput"/>
 3917    public abstract Stream ConvertTemporaryToFinal();
 3918
 3919    /// <summary>
 3920    /// Make a temporary copy of a <see cref="Stream"/>.
 3921    /// </summary>
 3922    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>
 3923    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3924    public abstract Stream MakeTemporaryCopy(Stream stream);
 3925
 3926    /// <summary>
 3927    /// Return a stream suitable for performing direct updates on the original source.
 3928    /// </summary>
 3929    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>
 3930    /// <returns>Returns a stream suitable for direct updating.</returns>
 3931    public abstract Stream OpenForDirectUpdate(Stream stream);
 3932
 3933    /// <summary>
 3934    /// Disposes this instance.
 3935    /// </summary>
 3936    public abstract void Dispose();
 3937
 3938    /// <summary>
 3939    /// Gets the update mode applicable.
 3940    /// </summary>
 3941    /// <value>The update mode.</value>
 3942    public FileUpdateMode UpdateMode {
 3943      get {
 3944        return updateMode_;
 3945      }
 3946    }
 3947
 3948    #endregion
 3949
 3950    #region Instance Fields
 3951    FileUpdateMode updateMode_;
 3952    #endregion
 3953  }
 3954
 3955  /// <summary>
 3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.
 3957  /// </summary>
 3958  public class DiskArchiveStorage : BaseArchiveStorage
 3959  {
 3960    #region Constructors
 3961    /// <summary>
 3962    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3963    /// </summary>
 3964    /// <param name="file">The file.</param>
 3965    /// <param name="updateMode">The update mode.</param>
 3966    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)
 113967      : base(updateMode)
 3968    {
 113969       if (file.Name == null) {
 03970        throw new ZipException("Cant handle non file archives");
 3971      }
 3972
 113973      fileName_ = file.Name;
 113974    }
 3975
 3976    /// <summary>
 3977    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3978    /// </summary>
 3979    /// <param name="file">The file.</param>
 3980    public DiskArchiveStorage(ZipFile file)
 103981      : this(file, FileUpdateMode.Safe)
 3982    {
 103983    }
 3984    #endregion
 3985
 3986    #region IArchiveStorage Members
 3987
 3988    /// <summary>
 3989    /// Gets a temporary output <see cref="Stream"/> for performing updates on.
 3990    /// </summary>
 3991    /// <returns>Returns the temporary output stream.</returns>
 3992    public override Stream GetTemporaryOutput()
 3993    {
 23994       if (temporaryName_ != null) {
 03995        temporaryName_ = GetTempFileName(temporaryName_, true);
 03996        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 03997      } else {
 3998        // Determine where to place files based on internal strategy.
 3999        // Currently this is always done in system temp directory.
 24000        temporaryName_ = Path.GetTempFileName();
 24001        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 4002      }
 4003
 24004      return temporaryStream_;
 4005    }
 4006
 4007    /// <summary>
 4008    /// Converts a temporary <see cref="Stream"/> to its final form.
 4009    /// </summary>
 4010    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4011    /// the final storage for the archive.</returns>
 4012    public override Stream ConvertTemporaryToFinal()
 4013    {
 34014       if (temporaryStream_ == null) {
 04015        throw new ZipException("No temporary stream has been created");
 4016      }
 4017
 34018      Stream result = null;
 4019
 34020      string moveTempName = GetTempFileName(fileName_, false);
 34021      bool newFileCreated = false;
 4022
 4023      try {
 34024        temporaryStream_.Close();
 34025        File.Move(fileName_, moveTempName);
 34026        File.Move(temporaryName_, fileName_);
 34027        newFileCreated = true;
 34028        File.Delete(moveTempName);
 4029
 34030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 34031      } catch (Exception) {
 04032        result = null;
 4033
 4034        // Try to roll back changes...
 04035         if (!newFileCreated) {
 04036          File.Move(moveTempName, fileName_);
 04037          File.Delete(temporaryName_);
 4038        }
 4039
 04040        throw;
 4041      }
 4042
 34043      return result;
 4044    }
 4045
 4046    /// <summary>
 4047    /// Make a temporary copy of a stream.
 4048    /// </summary>
 4049    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4050    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4051    public override Stream MakeTemporaryCopy(Stream stream)
 4052    {
 14053      stream.Close();
 4054
 14055      temporaryName_ = GetTempFileName(fileName_, true);
 14056      File.Copy(fileName_, temporaryName_, true);
 4057
 14058      temporaryStream_ = new FileStream(temporaryName_,
 14059        FileMode.Open,
 14060        FileAccess.ReadWrite);
 14061      return temporaryStream_;
 4062    }
 4063
 4064    /// <summary>
 4065    /// Return a stream suitable for performing direct updates on the original source.
 4066    /// </summary>
 4067    /// <param name="stream">The current stream.</param>
 4068    /// <returns>Returns a stream suitable for direct updating.</returns>
 4069    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>
 4070    public override Stream OpenForDirectUpdate(Stream stream)
 4071    {
 4072      Stream result;
 14073       if ((stream == null) || !stream.CanWrite) {
 14074         if (stream != null) {
 14075          stream.Close();
 4076        }
 4077
 14078        result = new FileStream(fileName_,
 14079            FileMode.Open,
 14080            FileAccess.ReadWrite);
 14081      } else {
 04082        result = stream;
 4083      }
 4084
 14085      return result;
 4086    }
 4087
 4088    /// <summary>
 4089    /// Disposes this instance.
 4090    /// </summary>
 4091    public override void Dispose()
 4092    {
 114093       if (temporaryStream_ != null) {
 34094        temporaryStream_.Close();
 4095      }
 114096    }
 4097
 4098    #endregion
 4099
 4100    #region Internal routines
 4101    static string GetTempFileName(string original, bool makeTempFile)
 4102    {
 44103      string result = null;
 4104
 44105       if (original == null) {
 04106        result = Path.GetTempFileName();
 04107      } else {
 44108        int counter = 0;
 44109        int suffixSeed = DateTime.Now.Second;
 4110
 94111         while (result == null) {
 54112          counter += 1;
 54113          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);
 54114           if (!File.Exists(newName)) {
 44115             if (makeTempFile) {
 4116              try {
 4117                // Try and create the file.
 14118                using (FileStream stream = File.Create(newName)) {
 14119                }
 14120                result = newName;
 14121              } catch {
 04122                suffixSeed = DateTime.Now.Second;
 04123              }
 4124            } else {
 34125              result = newName;
 4126            }
 4127          }
 4128        }
 4129      }
 44130      return result;
 4131    }
 4132    #endregion
 4133
 4134    #region Instance Fields
 4135    Stream temporaryStream_;
 4136    string fileName_;
 4137    string temporaryName_;
 4138    #endregion
 4139  }
 4140
 4141  /// <summary>
 4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.
 4143  /// </summary>
 4144  public class MemoryArchiveStorage : BaseArchiveStorage
 4145  {
 4146    #region Constructors
 4147    /// <summary>
 4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4149    /// </summary>
 4150    public MemoryArchiveStorage()
 4151      : base(FileUpdateMode.Direct)
 4152    {
 4153    }
 4154
 4155    /// <summary>
 4156    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4157    /// </summary>
 4158    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>
 4159    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>
 4160    public MemoryArchiveStorage(FileUpdateMode updateMode)
 4161      : base(updateMode)
 4162    {
 4163    }
 4164
 4165    #endregion
 4166
 4167    #region Properties
 4168    /// <summary>
 4169    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.
 4170    /// </summary>
 4171    public MemoryStream FinalStream {
 4172      get { return finalStream_; }
 4173    }
 4174
 4175    #endregion
 4176
 4177    #region IArchiveStorage Members
 4178
 4179    /// <summary>
 4180    /// Gets the temporary output <see cref="Stream"/>
 4181    /// </summary>
 4182    /// <returns>Returns the temporary output stream.</returns>
 4183    public override Stream GetTemporaryOutput()
 4184    {
 4185      temporaryStream_ = new MemoryStream();
 4186      return temporaryStream_;
 4187    }
 4188
 4189    /// <summary>
 4190    /// Converts the temporary <see cref="Stream"/> to its final form.
 4191    /// </summary>
 4192    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4193    /// the final storage for the archive.</returns>
 4194    public override Stream ConvertTemporaryToFinal()
 4195    {
 4196      if (temporaryStream_ == null) {
 4197        throw new ZipException("No temporary stream has been created");
 4198      }
 4199
 4200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());
 4201      return finalStream_;
 4202    }
 4203
 4204    /// <summary>
 4205    /// Make a temporary copy of the original stream.
 4206    /// </summary>
 4207    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4208    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4209    public override Stream MakeTemporaryCopy(Stream stream)
 4210    {
 4211      temporaryStream_ = new MemoryStream();
 4212      stream.Position = 0;
 4213      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);
 4214      return temporaryStream_;
 4215    }
 4216
 4217    /// <summary>
 4218    /// Return a stream suitable for performing direct updates on the original source.
 4219    /// </summary>
 4220    /// <param name="stream">The original source stream</param>
 4221    /// <returns>Returns a stream suitable for direct updating.</returns>
 4222    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;
 4223    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>
 4224    public override Stream OpenForDirectUpdate(Stream stream)
 4225    {
 4226      Stream result;
 4227      if ((stream == null) || !stream.CanWrite) {
 4228
 4229        result = new MemoryStream();
 4230
 4231        if (stream != null) {
 4232          stream.Position = 0;
 4233          StreamUtils.Copy(stream, result, new byte[4096]);
 4234
 4235          stream.Close();
 4236        }
 4237      } else {
 4238        result = stream;
 4239      }
 4240
 4241      return result;
 4242    }
 4243
 4244    /// <summary>
 4245    /// Disposes this instance.
 4246    /// </summary>
 4247    public override void Dispose()
 4248    {
 4249      if (temporaryStream_ != null) {
 4250        temporaryStream_.Close();
 4251      }
 4252    }
 4253
 4254    #endregion
 4255
 4256    #region Instance Fields
 4257    MemoryStream temporaryStream_;
 4258    MemoryStream finalStream_;
 4259    #endregion
 4260  }
 4261
 4262  #endregion
 4263}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_DynamicDiskDataSource.htm b/docs/opencover/ICSharpCode.SharpZipLib_DynamicDiskDataSource.htm new file mode 100644 index 000000000..661985474 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_DynamicDiskDataSource.htm @@ -0,0 +1,4305 @@ + + + + +ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs
Covered lines:4
Uncovered lines:0
Coverable lines:4
Total lines:4263
Line coverage:100%
Branch coverage:100%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
GetSource(...)2100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.IO;
 4using System.Text;
 5using System.Globalization;
 6using System.Security.Cryptography;
 7using ICSharpCode.SharpZipLib.Encryption;
 8using ICSharpCode.SharpZipLib.Core;
 9using ICSharpCode.SharpZipLib.Checksum;
 10using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 11using ICSharpCode.SharpZipLib.Zip.Compression;
 12
 13namespace ICSharpCode.SharpZipLib.Zip
 14{
 15  #region Keys Required Event Args
 16  /// <summary>
 17  /// Arguments used with KeysRequiredEvent
 18  /// </summary>
 19  public class KeysRequiredEventArgs : EventArgs
 20  {
 21    #region Constructors
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 24    /// </summary>
 25    /// <param name="name">The name of the file for which keys are required.</param>
 26    public KeysRequiredEventArgs(string name)
 27    {
 28      fileName = name;
 29    }
 30
 31    /// <summary>
 32    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 33    /// </summary>
 34    /// <param name="name">The name of the file for which keys are required.</param>
 35    /// <param name="keyValue">The current key value.</param>
 36    public KeysRequiredEventArgs(string name, byte[] keyValue)
 37    {
 38      fileName = name;
 39      key = keyValue;
 40    }
 41
 42    #endregion
 43    #region Properties
 44    /// <summary>
 45    /// Gets the name of the file for which keys are required.
 46    /// </summary>
 47    public string FileName {
 48      get { return fileName; }
 49    }
 50
 51    /// <summary>
 52    /// Gets or sets the key value
 53    /// </summary>
 54    public byte[] Key {
 55      get { return key; }
 56      set { key = value; }
 57    }
 58    #endregion
 59
 60    #region Instance Fields
 61    string fileName;
 62    byte[] key;
 63    #endregion
 64  }
 65  #endregion
 66
 67  #region Test Definitions
 68  /// <summary>
 69  /// The strategy to apply to testing.
 70  /// </summary>
 71  public enum TestStrategy
 72  {
 73    /// <summary>
 74    /// Find the first error only.
 75    /// </summary>
 76    FindFirstError,
 77    /// <summary>
 78    /// Find all possible errors.
 79    /// </summary>
 80    FindAllErrors,
 81  }
 82
 83  /// <summary>
 84  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.
 85  /// </summary>
 86  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 87  public enum TestOperation
 88  {
 89    /// <summary>
 90    /// Setting up testing.
 91    /// </summary>
 92    Initialising,
 93
 94    /// <summary>
 95    /// Testing an individual entries header
 96    /// </summary>
 97    EntryHeader,
 98
 99    /// <summary>
 100    /// Testing an individual entries data
 101    /// </summary>
 102    EntryData,
 103
 104    /// <summary>
 105    /// Testing an individual entry has completed.
 106    /// </summary>
 107    EntryComplete,
 108
 109    /// <summary>
 110    /// Running miscellaneous tests
 111    /// </summary>
 112    MiscellaneousTests,
 113
 114    /// <summary>
 115    /// Testing is complete
 116    /// </summary>
 117    Complete,
 118  }
 119
 120  /// <summary>
 121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.
 122  /// </summary>
 123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 124  public class TestStatus
 125  {
 126    #region Constructors
 127    /// <summary>
 128    /// Initialise a new instance of <see cref="TestStatus"/>
 129    /// </summary>
 130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>
 131    public TestStatus(ZipFile file)
 132    {
 133      file_ = file;
 134    }
 135    #endregion
 136
 137    #region Properties
 138
 139    /// <summary>
 140    /// Get the current <see cref="TestOperation"/> in progress.
 141    /// </summary>
 142    public TestOperation Operation {
 143      get { return operation_; }
 144    }
 145
 146    /// <summary>
 147    /// Get the <see cref="ZipFile"/> this status is applicable to.
 148    /// </summary>
 149    public ZipFile File {
 150      get { return file_; }
 151    }
 152
 153    /// <summary>
 154    /// Get the current/last entry tested.
 155    /// </summary>
 156    public ZipEntry Entry {
 157      get { return entry_; }
 158    }
 159
 160    /// <summary>
 161    /// Get the number of errors detected so far.
 162    /// </summary>
 163    public int ErrorCount {
 164      get { return errorCount_; }
 165    }
 166
 167    /// <summary>
 168    /// Get the number of bytes tested so far for the current entry.
 169    /// </summary>
 170    public long BytesTested {
 171      get { return bytesTested_; }
 172    }
 173
 174    /// <summary>
 175    /// Get a value indicating wether the last entry test was valid.
 176    /// </summary>
 177    public bool EntryValid {
 178      get { return entryValid_; }
 179    }
 180    #endregion
 181
 182    #region Internal API
 183    internal void AddError()
 184    {
 185      errorCount_++;
 186      entryValid_ = false;
 187    }
 188
 189    internal void SetOperation(TestOperation operation)
 190    {
 191      operation_ = operation;
 192    }
 193
 194    internal void SetEntry(ZipEntry entry)
 195    {
 196      entry_ = entry;
 197      entryValid_ = true;
 198      bytesTested_ = 0;
 199    }
 200
 201    internal void SetBytesTested(long value)
 202    {
 203      bytesTested_ = value;
 204    }
 205    #endregion
 206
 207    #region Instance Fields
 208    ZipFile file_;
 209    ZipEntry entry_;
 210    bool entryValid_;
 211    int errorCount_;
 212    long bytesTested_;
 213    TestOperation operation_;
 214    #endregion
 215  }
 216
 217  /// <summary>
 218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if
 219  /// </summary>
 220  /// <remarks>If the message is non-null an error has occured.  If the message is null
 221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>
 222  public delegate void ZipTestResultHandler(TestStatus status, string message);
 223  #endregion
 224
 225  #region Update Definitions
 226  /// <summary>
 227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.
 228  /// </summary>
 229  public enum FileUpdateMode
 230  {
 231    /// <summary>
 232    /// Perform all updates on temporary files ensuring that the original file is saved.
 233    /// </summary>
 234    Safe,
 235    /// <summary>
 236    /// Update the archive directly, which is faster but less safe.
 237    /// </summary>
 238    Direct,
 239  }
 240  #endregion
 241
 242  #region ZipFile Class
 243  /// <summary>
 244  /// This class represents a Zip archive.  You can ask for the contained
 245  /// entries, or get an input stream for a file entry.  The entry is
 246  /// automatically decompressed.
 247  ///
 248  /// You can also update the archive adding or deleting entries.
 249  ///
 250  /// This class is thread safe for input:  You can open input streams for arbitrary
 251  /// entries in different threads.
 252  /// <br/>
 253  /// <br/>Author of the original java version : Jochen Hoenicke
 254  /// </summary>
 255  /// <example>
 256  /// <code>
 257  /// using System;
 258  /// using System.Text;
 259  /// using System.Collections;
 260  /// using System.IO;
 261  ///
 262  /// using ICSharpCode.SharpZipLib.Zip;
 263  ///
 264  /// class MainClass
 265  /// {
 266  ///   static public void Main(string[] args)
 267  ///   {
 268  ///     using (ZipFile zFile = new ZipFile(args[0])) {
 269  ///       Console.WriteLine("Listing of : " + zFile.Name);
 270  ///       Console.WriteLine("");
 271  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");
 272  ///       Console.WriteLine("--------  --------  --------  ------  ---------");
 273  ///       foreach (ZipEntry e in zFile) {
 274  ///         if ( e.IsFile ) {
 275  ///           DateTime d = e.DateTime;
 276  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,
 277  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),
 278  ///             e.Name);
 279  ///         }
 280  ///       }
 281  ///     }
 282  ///   }
 283  /// }
 284  /// </code>
 285  /// </example>
 286  public class ZipFile : IEnumerable, IDisposable
 287  {
 288    #region KeyHandling
 289
 290    /// <summary>
 291    /// Delegate for handling keys/password setting during compresion/decompression.
 292    /// </summary>
 293    public delegate void KeysRequiredEventHandler(
 294      object sender,
 295      KeysRequiredEventArgs e
 296    );
 297
 298    /// <summary>
 299    /// Event handler for handling encryption keys.
 300    /// </summary>
 301    public KeysRequiredEventHandler KeysRequired;
 302
 303    /// <summary>
 304    /// Handles getting of encryption keys when required.
 305    /// </summary>
 306    /// <param name="fileName">The file for which encryption keys are required.</param>
 307    void OnKeysRequired(string fileName)
 308    {
 309      if (KeysRequired != null) {
 310        var krea = new KeysRequiredEventArgs(fileName, key);
 311        KeysRequired(this, krea);
 312        key = krea.Key;
 313      }
 314    }
 315
 316    /// <summary>
 317    /// Get/set the encryption key value.
 318    /// </summary>
 319    byte[] Key {
 320      get { return key; }
 321      set { key = value; }
 322    }
 323
 324    /// <summary>
 325    /// Password to be used for encrypting/decrypting files.
 326    /// </summary>
 327    /// <remarks>Set to null if no password is required.</remarks>
 328    public string Password {
 329      set {
 330        if (string.IsNullOrEmpty(value)) {
 331          key = null;
 332        } else {
 333          rawPassword_ = value;
 334          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));
 335        }
 336      }
 337    }
 338
 339    /// <summary>
 340    /// Get a value indicating wether encryption keys are currently available.
 341    /// </summary>
 342    bool HaveKeys {
 343      get { return key != null; }
 344    }
 345    #endregion
 346
 347    #region Constructors
 348    /// <summary>
 349    /// Opens a Zip file with the given name for reading.
 350    /// </summary>
 351    /// <param name="name">The name of the file to open.</param>
 352    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>
 353    /// <exception cref="IOException">
 354    /// An i/o error occurs
 355    /// </exception>
 356    /// <exception cref="ZipException">
 357    /// The file doesn't contain a valid zip archive.
 358    /// </exception>
 359    public ZipFile(string name)
 360    {
 361      if (name == null) {
 362        throw new ArgumentNullException(nameof(name));
 363      }
 364
 365      name_ = name;
 366
 367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 368      isStreamOwner = true;
 369
 370      try {
 371        ReadEntries();
 372      } catch {
 373        DisposeInternal(true);
 374        throw;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Opens a Zip file reading the given <see cref="FileStream"/>.
 380    /// </summary>
 381    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>
 382    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>
 383    /// <exception cref="IOException">
 384    /// An i/o error occurs.
 385    /// </exception>
 386    /// <exception cref="ZipException">
 387    /// The file doesn't contain a valid zip archive.
 388    /// </exception>
 389    public ZipFile(FileStream file)
 390    {
 391      if (file == null) {
 392        throw new ArgumentNullException(nameof(file));
 393      }
 394
 395      if (!file.CanSeek) {
 396        throw new ArgumentException("Stream is not seekable", nameof(file));
 397      }
 398
 399      baseStream_ = file;
 400      name_ = file.Name;
 401      isStreamOwner = true;
 402
 403      try {
 404        ReadEntries();
 405      } catch {
 406        DisposeInternal(true);
 407        throw;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Opens a Zip file reading the given <see cref="Stream"/>.
 413    /// </summary>
 414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
 415    /// <exception cref="IOException">
 416    /// An i/o error occurs
 417    /// </exception>
 418    /// <exception cref="ZipException">
 419    /// The stream doesn't contain a valid zip archive.<br/>
 420    /// </exception>
 421    /// <exception cref="ArgumentException">
 422    /// The <see cref="Stream">stream</see> doesnt support seeking.
 423    /// </exception>
 424    /// <exception cref="ArgumentNullException">
 425    /// The <see cref="Stream">stream</see> argument is null.
 426    /// </exception>
 427    public ZipFile(Stream stream)
 428    {
 429      if (stream == null) {
 430        throw new ArgumentNullException(nameof(stream));
 431      }
 432
 433      if (!stream.CanSeek) {
 434        throw new ArgumentException("Stream is not seekable", nameof(stream));
 435      }
 436
 437      baseStream_ = stream;
 438      isStreamOwner = true;
 439
 440      if (baseStream_.Length > 0) {
 441        try {
 442          ReadEntries();
 443        } catch {
 444          DisposeInternal(true);
 445          throw;
 446        }
 447      } else {
 448        entries_ = new ZipEntry[0];
 449        isNewArchive_ = true;
 450      }
 451    }
 452
 453    /// <summary>
 454    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
 455    /// </summary>
 456    internal ZipFile()
 457    {
 458      entries_ = new ZipEntry[0];
 459      isNewArchive_ = true;
 460    }
 461
 462    #endregion
 463
 464    #region Destructors and Closing
 465    /// <summary>
 466    /// Finalize this instance.
 467    /// </summary>
 468    ~ZipFile()
 469    {
 470      Dispose(false);
 471    }
 472
 473    /// <summary>
 474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying
 475    /// Once closed, no further instance methods should be called.
 476    /// </summary>
 477    /// <exception cref="System.IO.IOException">
 478    /// An i/o error occurs.
 479    /// </exception>
 480    public void Close()
 481    {
 482      DisposeInternal(true);
 483      GC.SuppressFinalize(this);
 484    }
 485
 486    #endregion
 487
 488    #region Creators
 489    /// <summary>
 490    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.
 491    /// </summary>
 492    /// <param name="fileName">The name of the archive to create.</param>
 493    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 494    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>
 495    public static ZipFile Create(string fileName)
 496    {
 497      if (fileName == null) {
 498        throw new ArgumentNullException(nameof(fileName));
 499      }
 500
 501      FileStream fs = File.Create(fileName);
 502
 503      var result = new ZipFile();
 504      result.name_ = fileName;
 505      result.baseStream_ = fs;
 506      result.isStreamOwner = true;
 507      return result;
 508    }
 509
 510    /// <summary>
 511    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.
 512    /// </summary>
 513    /// <param name="outStream">The stream providing data storage.</param>
 514    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 515    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>
 516    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>
 517    public static ZipFile Create(Stream outStream)
 518    {
 519      if (outStream == null) {
 520        throw new ArgumentNullException(nameof(outStream));
 521      }
 522
 523      if (!outStream.CanWrite) {
 524        throw new ArgumentException("Stream is not writeable", nameof(outStream));
 525      }
 526
 527      if (!outStream.CanSeek) {
 528        throw new ArgumentException("Stream is not seekable", nameof(outStream));
 529      }
 530
 531      var result = new ZipFile();
 532      result.baseStream_ = outStream;
 533      return result;
 534    }
 535
 536    #endregion
 537
 538    #region Properties
 539    /// <summary>
 540    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
 541    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
 542    /// </summary>
 543    /// <remarks>
 544    /// The default value is true in all cases.
 545    /// </remarks>
 546    public bool IsStreamOwner {
 547      get { return isStreamOwner; }
 548      set { isStreamOwner = value; }
 549    }
 550
 551    /// <summary>
 552    /// Get a value indicating wether
 553    /// this archive is embedded in another file or not.
 554    /// </summary>
 555    public bool IsEmbeddedArchive {
 556      // Not strictly correct in all circumstances currently
 557      get { return offsetOfFirstEntry > 0; }
 558    }
 559
 560    /// <summary>
 561    /// Get a value indicating that this archive is a new one.
 562    /// </summary>
 563    public bool IsNewArchive {
 564      get { return isNewArchive_; }
 565    }
 566
 567    /// <summary>
 568    /// Gets the comment for the zip file.
 569    /// </summary>
 570    public string ZipFileComment {
 571      get { return comment_; }
 572    }
 573
 574    /// <summary>
 575    /// Gets the name of this zip file.
 576    /// </summary>
 577    public string Name {
 578      get { return name_; }
 579    }
 580
 581    /// <summary>
 582    /// Gets the number of entries in this zip file.
 583    /// </summary>
 584    /// <exception cref="InvalidOperationException">
 585    /// The Zip file has been closed.
 586    /// </exception>
 587    [Obsolete("Use the Count property instead")]
 588    public int Size {
 589      get {
 590        return entries_.Length;
 591      }
 592    }
 593
 594    /// <summary>
 595    /// Get the number of entries contained in this <see cref="ZipFile"/>.
 596    /// </summary>
 597    public long Count {
 598      get {
 599        return entries_.Length;
 600      }
 601    }
 602
 603    /// <summary>
 604    /// Indexer property for ZipEntries
 605    /// </summary>
 606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
 607    public ZipEntry this[int index] {
 608      get {
 609        return (ZipEntry)entries_[index].Clone();
 610      }
 611    }
 612
 613    #endregion
 614
 615    #region Input Handling
 616    /// <summary>
 617    /// Gets an enumerator for the Zip entries in this Zip file.
 618    /// </summary>
 619    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>
 620    /// <exception cref="ObjectDisposedException">
 621    /// The Zip file has been closed.
 622    /// </exception>
 623    public IEnumerator GetEnumerator()
 624    {
 625      if (isDisposed_) {
 626        throw new ObjectDisposedException("ZipFile");
 627      }
 628
 629      return new ZipEntryEnumerator(entries_);
 630    }
 631
 632    /// <summary>
 633    /// Return the index of the entry with a matching name
 634    /// </summary>
 635    /// <param name="name">Entry name to find</param>
 636    /// <param name="ignoreCase">If true the comparison is case insensitive</param>
 637    /// <returns>The index position of the matching entry or -1 if not found</returns>
 638    /// <exception cref="ObjectDisposedException">
 639    /// The Zip file has been closed.
 640    /// </exception>
 641    public int FindEntry(string name, bool ignoreCase)
 642    {
 643      if (isDisposed_) {
 644        throw new ObjectDisposedException("ZipFile");
 645      }
 646
 647      // TODO: This will be slow as the next ice age for huge archives!
 648      for (int i = 0; i < entries_.Length; i++) {
 649        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {
 650          return i;
 651        }
 652      }
 653      return -1;
 654    }
 655
 656    /// <summary>
 657    /// Searches for a zip entry in this archive with the given name.
 658    /// String comparisons are case insensitive
 659    /// </summary>
 660    /// <param name="name">
 661    /// The name to find. May contain directory components separated by slashes ('/').
 662    /// </param>
 663    /// <returns>
 664    /// A clone of the zip entry, or null if no entry with that name exists.
 665    /// </returns>
 666    /// <exception cref="ObjectDisposedException">
 667    /// The Zip file has been closed.
 668    /// </exception>
 669    public ZipEntry GetEntry(string name)
 670    {
 671      if (isDisposed_) {
 672        throw new ObjectDisposedException("ZipFile");
 673      }
 674
 675      int index = FindEntry(name, true);
 676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;
 677    }
 678
 679    /// <summary>
 680    /// Gets an input stream for reading the given zip entry data in an uncompressed form.
 681    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
 682    /// </summary>
 683    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
 684    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
 685    /// <exception cref="ObjectDisposedException">
 686    /// The ZipFile has already been closed
 687    /// </exception>
 688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 689    /// The compression method for the entry is unknown
 690    /// </exception>
 691    /// <exception cref="IndexOutOfRangeException">
 692    /// The entry is not found in the ZipFile
 693    /// </exception>
 694    public Stream GetInputStream(ZipEntry entry)
 695    {
 696      if (entry == null) {
 697        throw new ArgumentNullException(nameof(entry));
 698      }
 699
 700      if (isDisposed_) {
 701        throw new ObjectDisposedException("ZipFile");
 702      }
 703
 704      long index = entry.ZipFileIndex;
 705      if ((index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name)) {
 706        index = FindEntry(entry.Name, true);
 707        if (index < 0) {
 708          throw new ZipException("Entry cannot be found");
 709        }
 710      }
 711      return GetInputStream(index);
 712    }
 713
 714    /// <summary>
 715    /// Creates an input stream reading a zip entry
 716    /// </summary>
 717    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
 718    /// <returns>
 719    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>
 720    /// </returns>
 721    /// <exception cref="ObjectDisposedException">
 722    /// The ZipFile has already been closed
 723    /// </exception>
 724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 725    /// The compression method for the entry is unknown
 726    /// </exception>
 727    /// <exception cref="IndexOutOfRangeException">
 728    /// The entry is not found in the ZipFile
 729    /// </exception>
 730    public Stream GetInputStream(long entryIndex)
 731    {
 732      if (isDisposed_) {
 733        throw new ObjectDisposedException("ZipFile");
 734      }
 735
 736      long start = LocateEntry(entries_[entryIndex]);
 737      CompressionMethod method = entries_[entryIndex].CompressionMethod;
 738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);
 739
 740      if (entries_[entryIndex].IsCrypted == true) {
 741        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);
 742        if (result == null) {
 743          throw new ZipException("Unable to decrypt this entry");
 744        }
 745      }
 746
 747      switch (method) {
 748        case CompressionMethod.Stored:
 749          // read as is.
 750          break;
 751
 752        case CompressionMethod.Deflated:
 753          // No need to worry about ownership and closing as underlying stream close does nothing.
 754          result = new InflaterInputStream(result, new Inflater(true));
 755          break;
 756
 757        default:
 758          throw new ZipException("Unsupported compression method " + method);
 759      }
 760
 761      return result;
 762    }
 763
 764    #endregion
 765
 766    #region Archive Testing
 767    /// <summary>
 768    /// Test an archive for integrity/validity
 769    /// </summary>
 770    /// <param name="testData">Perform low level data Crc check</param>
 771    /// <returns>true if all tests pass, false otherwise</returns>
 772    /// <remarks>Testing will terminate on the first error found.</remarks>
 773    public bool TestArchive(bool testData)
 774    {
 775      return TestArchive(testData, TestStrategy.FindFirstError, null);
 776    }
 777
 778    /// <summary>
 779    /// Test an archive for integrity/validity
 780    /// </summary>
 781    /// <param name="testData">Perform low level data Crc check</param>
 782    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
 783    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
 784    /// <returns>true if all tests pass, false otherwise</returns>
 785    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>
 786    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
 787    {
 788      if (isDisposed_) {
 789        throw new ObjectDisposedException("ZipFile");
 790      }
 791
 792      var status = new TestStatus(this);
 793
 794      if (resultHandler != null) {
 795        resultHandler(status, null);
 796      }
 797
 798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;
 799
 800      bool testing = true;
 801
 802      try {
 803        int entryIndex = 0;
 804
 805        while (testing && (entryIndex < Count)) {
 806          if (resultHandler != null) {
 807            status.SetEntry(this[entryIndex]);
 808            status.SetOperation(TestOperation.EntryHeader);
 809            resultHandler(status, null);
 810          }
 811
 812          try {
 813            TestLocalHeader(this[entryIndex], test);
 814          } catch (ZipException ex) {
 815            status.AddError();
 816
 817            if (resultHandler != null) {
 818              resultHandler(status,
 819                string.Format("Exception during test - '{0}'", ex.Message));
 820            }
 821
 822            testing &= strategy != TestStrategy.FindFirstError;
 823          }
 824
 825          if (testing && testData && this[entryIndex].IsFile) {
 826            if (resultHandler != null) {
 827              status.SetOperation(TestOperation.EntryData);
 828              resultHandler(status, null);
 829            }
 830
 831            var crc = new Crc32();
 832
 833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {
 834
 835              byte[] buffer = new byte[4096];
 836              long totalBytes = 0;
 837              int bytesRead;
 838              while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
 839                crc.Update(buffer, 0, bytesRead);
 840
 841                if (resultHandler != null) {
 842                  totalBytes += bytesRead;
 843                  status.SetBytesTested(totalBytes);
 844                  resultHandler(status, null);
 845                }
 846              }
 847            }
 848
 849            if (this[entryIndex].Crc != crc.Value) {
 850              status.AddError();
 851
 852              if (resultHandler != null) {
 853                resultHandler(status, "CRC mismatch");
 854              }
 855
 856              testing &= strategy != TestStrategy.FindFirstError;
 857            }
 858
 859            if ((this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 860              var helper = new ZipHelperStream(baseStream_);
 861              var data = new DescriptorData();
 862              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
 863              if (this[entryIndex].Crc != data.Crc) {
 864                status.AddError();
 865              }
 866
 867              if (this[entryIndex].CompressedSize != data.CompressedSize) {
 868                status.AddError();
 869              }
 870
 871              if (this[entryIndex].Size != data.Size) {
 872                status.AddError();
 873              }
 874            }
 875          }
 876
 877          if (resultHandler != null) {
 878            status.SetOperation(TestOperation.EntryComplete);
 879            resultHandler(status, null);
 880          }
 881
 882          entryIndex += 1;
 883        }
 884
 885        if (resultHandler != null) {
 886          status.SetOperation(TestOperation.MiscellaneousTests);
 887          resultHandler(status, null);
 888        }
 889
 890        // TODO: the 'Corrina Johns' test where local headers are missing from
 891        // the central directory.  They are therefore invisible to many archivers.
 892      } catch (Exception ex) {
 893        status.AddError();
 894
 895        if (resultHandler != null) {
 896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
 897        }
 898      }
 899
 900      if (resultHandler != null) {
 901        status.SetOperation(TestOperation.Complete);
 902        status.SetEntry(null);
 903        resultHandler(status, null);
 904      }
 905
 906      return (status.ErrorCount == 0);
 907    }
 908
 909    [Flags]
 910    enum HeaderTest
 911    {
 912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted
 913      Header = 0x02,     // Check that this header contents are valid
 914    }
 915
 916    /// <summary>
 917    /// Test a local header against that provided from the central directory
 918    /// </summary>
 919    /// <param name="entry">
 920    /// The entry to test against
 921    /// </param>
 922    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
 923    /// <returns>The offset of the entries data in the file</returns>
 924    long TestLocalHeader(ZipEntry entry, HeaderTest tests)
 925    {
 926      lock (baseStream_) {
 927        bool testHeader = (tests & HeaderTest.Header) != 0;
 928        bool testData = (tests & HeaderTest.Extract) != 0;
 929
 930        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
 931        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
 932          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)
 933        }
 934
 935        var extractVersion = (short)(ReadLEUshort() & 0x00ff);
 936        var localFlags = (short)ReadLEUshort();
 937        var compressionMethod = (short)ReadLEUshort();
 938        var fileTime = (short)ReadLEUshort();
 939        var fileDate = (short)ReadLEUshort();
 940        uint crcValue = ReadLEUint();
 941        long compressedSize = ReadLEUint();
 942        long size = ReadLEUint();
 943        int storedNameLength = ReadLEUshort();
 944        int extraDataLength = ReadLEUshort();
 945
 946        byte[] nameData = new byte[storedNameLength];
 947        StreamUtils.ReadFully(baseStream_, nameData);
 948
 949        byte[] extraData = new byte[extraDataLength];
 950        StreamUtils.ReadFully(baseStream_, extraData);
 951
 952        var localExtraData = new ZipExtraData(extraData);
 953
 954        // Extra data / zip64 checks
 955        if (localExtraData.Find(1)) {
 956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
 957          // and size or compressedSize = MaxValue, due to rogue creators.
 958
 959          size = localExtraData.ReadLong();
 960          compressedSize = localExtraData.ReadLong();
 961
 962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {
 963            // These may be valid if patched later
 964            if ((size != -1) && (size != entry.Size)) {
 965              throw new ZipException("Size invalid for descriptor");
 966            }
 967
 968            if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {
 969              throw new ZipException("Compressed size invalid for descriptor");
 970            }
 971          }
 972        } else {
 973          // No zip64 extra data but entry requires it.
 974          if ((extractVersion >= ZipConstants.VersionZip64) &&
 975            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) {
 976            throw new ZipException("Required Zip64 extended information missing");
 977          }
 978        }
 979
 980        if (testData) {
 981          if (entry.IsFile) {
 982            if (!entry.IsCompressionMethodSupported()) {
 983              throw new ZipException("Compression method not supported");
 984            }
 985
 986            if ((extractVersion > ZipConstants.VersionMadeBy)
 987              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64))) {
 988              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract
 989            }
 990
 991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance
 992              throw new ZipException("The library does not support the zip version required to extract this entry");
 993            }
 994          }
 995        }
 996
 997        if (testHeader) {
 998          if ((extractVersion <= 63) &&   // Ignore later versions as we dont know about them..
 999            (extractVersion != 10) &&
 1000            (extractVersion != 11) &&
 1001            (extractVersion != 20) &&
 1002            (extractVersion != 21) &&
 1003            (extractVersion != 25) &&
 1004            (extractVersion != 27) &&
 1005            (extractVersion != 45) &&
 1006            (extractVersion != 46) &&
 1007            (extractVersion != 50) &&
 1008            (extractVersion != 51) &&
 1009            (extractVersion != 52) &&
 1010            (extractVersion != 61) &&
 1011            (extractVersion != 62) &&
 1012            (extractVersion != 63)
 1013            ) {
 1014            throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersi
 1015          }
 1016
 1017          // Local entry flags dont have reserved bit set on.
 1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R
 1019            throw new ZipException("Reserved bit flags cannot be set.");
 1020          }
 1021
 1022          // Encryption requires extract version >= 20
 1023          if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) {
 1024            throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})
 1025          }
 1026
 1027          // Strong encryption requires encryption flag to be set and extract version >= 50.
 1028          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1029            if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) {
 1030              throw new ZipException("Strong encryption flag set but encryption flag is not set");
 1031            }
 1032
 1033            if (extractVersion < 50) {
 1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0
 1035            }
 1036          }
 1037
 1038          // Patched entries require extract version >= 27
 1039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {
 1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
 1041          }
 1042
 1043          // Central header flags match local entry flags.
 1044          if (localFlags != entry.Flags) {
 1045            throw new ZipException("Central header/local header flags mismatch");
 1046          }
 1047
 1048          // Central header compression method matches local entry
 1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {
 1050            throw new ZipException("Central header/local header compression method mismatch");
 1051          }
 1052
 1053          if (entry.Version != extractVersion) {
 1054            throw new ZipException("Extract version mismatch");
 1055          }
 1056
 1057          // Strong encryption and extract version match
 1058          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1059            if (extractVersion < 62) {
 1060              throw new ZipException("Strong encryption flag set but version not high enough");
 1061            }
 1062          }
 1063
 1064          if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) {
 1065            if ((fileTime != 0) || (fileDate != 0)) {
 1066              throw new ZipException("Header masked set but date/time values non-zero");
 1067            }
 1068          }
 1069
 1070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
 1071            if (crcValue != (uint)entry.Crc) {
 1072              throw new ZipException("Central header/local header crc mismatch");
 1073            }
 1074          }
 1075
 1076          // Crc valid for empty entry.
 1077          // This will also apply to streamed entries where size isnt known and the header cant be patched
 1078          if ((size == 0) && (compressedSize == 0)) {
 1079            if (crcValue != 0) {
 1080              throw new ZipException("Invalid CRC for empty entry");
 1081            }
 1082          }
 1083
 1084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str
 1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
 1086          if (entry.Name.Length > storedNameLength) {
 1087            throw new ZipException("File name length mismatch");
 1088          }
 1089
 1090          // Name data has already been read convert it and compare.
 1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);
 1092
 1093          // Central directory and local entry name match
 1094          if (localName != entry.Name) {
 1095            throw new ZipException("Central header and local header file name mismatch");
 1096          }
 1097
 1098          // Directories have zero actual size but can have compressed size
 1099          if (entry.IsDirectory) {
 1100            if (size > 0) {
 1101              throw new ZipException("Directory cannot have size");
 1102            }
 1103
 1104            // There may be other cases where the compressed size can be greater than this?
 1105            // If so until details are known we will be strict.
 1106            if (entry.IsCrypted) {
 1107              if (compressedSize > ZipConstants.CryptoHeaderSize + 2) {
 1108                throw new ZipException("Directory compressed size invalid");
 1109              }
 1110            } else if (compressedSize > 2) {
 1111              // When not compressed the directory size can validly be 2 bytes
 1112              // if the true size wasnt known when data was originally being written.
 1113              // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
 1114              throw new ZipException("Directory compressed size invalid");
 1115            }
 1116          }
 1117
 1118          if (!ZipNameTransform.IsValidName(localName, true)) {
 1119            throw new ZipException("Name is invalid");
 1120          }
 1121        }
 1122
 1123        // Tests that apply to both data and header.
 1124
 1125        // Size can be verified only if it is known in the local header.
 1126        // it will always be known in the central header.
 1127        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
 1128          ((size > 0 || compressedSize > 0) && entry.Size > 0)) {
 1129
 1130          if ((size != 0)
 1131            && (size != entry.Size)) {
 1132            throw new ZipException(
 1133              string.Format("Size mismatch between central header({0}) and local header({1})",
 1134                entry.Size, size));
 1135          }
 1136
 1137          if ((compressedSize != 0)
 1138            && (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) {
 1139            throw new ZipException(
 1140              string.Format("Compressed size mismatch between central header({0}) and local header({1})",
 1141              entry.CompressedSize, compressedSize));
 1142          }
 1143        }
 1144
 1145        int extraLength = storedNameLength + extraDataLength;
 1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
 1147      }
 1148    }
 1149
 1150    #endregion
 1151
 1152    #region Updating
 1153
 1154    const int DefaultBufferSize = 4096;
 1155
 1156    /// <summary>
 1157    /// The kind of update to apply.
 1158    /// </summary>
 1159    enum UpdateCommand
 1160    {
 1161      Copy,       // Copy original file contents.
 1162      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.
 1163      Add,        // Add a new file to the archive.
 1164    }
 1165
 1166    #region Properties
 1167    /// <summary>
 1168    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.
 1169    /// </summary>
 1170    public INameTransform NameTransform {
 1171      get {
 1172        return updateEntryFactory_.NameTransform;
 1173      }
 1174
 1175      set {
 1176        updateEntryFactory_.NameTransform = value;
 1177      }
 1178    }
 1179
 1180    /// <summary>
 1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values
 1182    /// during updates.
 1183    /// </summary>
 1184    public IEntryFactory EntryFactory {
 1185      get {
 1186        return updateEntryFactory_;
 1187      }
 1188
 1189      set {
 1190        if (value == null) {
 1191          updateEntryFactory_ = new ZipEntryFactory();
 1192        } else {
 1193          updateEntryFactory_ = value;
 1194        }
 1195      }
 1196    }
 1197
 1198    /// <summary>
 1199    /// Get /set the buffer size to be used when updating this zip file.
 1200    /// </summary>
 1201    public int BufferSize {
 1202      get { return bufferSize_; }
 1203      set {
 1204        if (value < 1024) {
 1205          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");
 1206        }
 1207
 1208        if (bufferSize_ != value) {
 1209          bufferSize_ = value;
 1210          copyBuffer_ = null;
 1211        }
 1212      }
 1213    }
 1214
 1215    /// <summary>
 1216    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.
 1217    /// </summary>
 1218    public bool IsUpdating {
 1219      get { return updates_ != null; }
 1220    }
 1221
 1222    /// <summary>
 1223    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
 1224    /// </summary>
 1225    public UseZip64 UseZip64 {
 1226      get { return useZip64_; }
 1227      set { useZip64_ = value; }
 1228    }
 1229
 1230    #endregion
 1231
 1232    #region Immediate updating
 1233    //    TBD: Direct form of updating
 1234    //
 1235    //    public void Update(IEntryMatcher deleteMatcher)
 1236    //    {
 1237    //    }
 1238    //
 1239    //    public void Update(IScanner addScanner)
 1240    //    {
 1241    //    }
 1242    #endregion
 1243
 1244    #region Deferred Updating
 1245    /// <summary>
 1246    /// Begin updating this <see cref="ZipFile"/> archive.
 1247    /// </summary>
 1248    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p
 1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param
 1250    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1251    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>
 1252    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1253    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)
 1254    {
 1255      if (archiveStorage == null) {
 1256        throw new ArgumentNullException(nameof(archiveStorage));
 1257      }
 1258
 1259      if (dataSource == null) {
 1260        throw new ArgumentNullException(nameof(dataSource));
 1261      }
 1262
 1263      if (isDisposed_) {
 1264        throw new ObjectDisposedException("ZipFile");
 1265      }
 1266
 1267      if (IsEmbeddedArchive) {
 1268        throw new ZipException("Cannot update embedded/SFX archives");
 1269      }
 1270
 1271      archiveStorage_ = archiveStorage;
 1272      updateDataSource_ = dataSource;
 1273
 1274      // NOTE: the baseStream_ may not currently support writing or seeking.
 1275
 1276      updateIndex_ = new Hashtable();
 1277
 1278      updates_ = new ArrayList(entries_.Length);
 1279      foreach (ZipEntry entry in entries_) {
 1280        int index = updates_.Add(new ZipUpdate(entry));
 1281        updateIndex_.Add(entry.Name, index);
 1282      }
 1283
 1284      // We must sort by offset before using offset's calculated sizes
 1285      updates_.Sort(new UpdateComparer());
 1286
 1287      int idx = 0;
 1288      foreach (ZipUpdate update in updates_) {
 1289        //If last entry, there is no next entry offset to use
 1290        if (idx == updates_.Count - 1)
 1291          break;
 1292
 1293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;
 1294        idx++;
 1295      }
 1296      updateCount_ = updates_.Count;
 1297
 1298      contentsEdited_ = false;
 1299      commentEdited_ = false;
 1300      newComment_ = null;
 1301    }
 1302
 1303    /// <summary>
 1304    /// Begin updating to this <see cref="ZipFile"/> archive.
 1305    /// </summary>
 1306    /// <param name="archiveStorage">The storage to use during the update.</param>
 1307    public void BeginUpdate(IArchiveStorage archiveStorage)
 1308    {
 1309      BeginUpdate(archiveStorage, new DynamicDiskDataSource());
 1310    }
 1311
 1312    /// <summary>
 1313    /// Begin updating this <see cref="ZipFile"/> archive.
 1314    /// </summary>
 1315    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>
 1316    /// <seealso cref="CommitUpdate"></seealso>
 1317    /// <seealso cref="AbortUpdate"></seealso>
 1318    public void BeginUpdate()
 1319    {
 1320      if (Name == null) {
 1321        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());
 1322      } else {
 1323        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());
 1324      }
 1325    }
 1326
 1327    /// <summary>
 1328    /// Commit current updates, updating this archive.
 1329    /// </summary>
 1330    /// <seealso cref="BeginUpdate()"></seealso>
 1331    /// <seealso cref="AbortUpdate"></seealso>
 1332    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1333    public void CommitUpdate()
 1334    {
 1335      if (isDisposed_) {
 1336        throw new ObjectDisposedException("ZipFile");
 1337      }
 1338
 1339      CheckUpdating();
 1340
 1341      try {
 1342        updateIndex_.Clear();
 1343        updateIndex_ = null;
 1344
 1345        if (contentsEdited_) {
 1346          RunUpdates();
 1347        } else if (commentEdited_) {
 1348          UpdateCommentOnly();
 1349        } else {
 1350          // Create an empty archive if none existed originally.
 1351          if (entries_.Length == 0) {
 1352            byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 1353            using (ZipHelperStream zhs = new ZipHelperStream(baseStream_)) {
 1354              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
 1355            }
 1356          }
 1357        }
 1358
 1359      } finally {
 1360        PostUpdateCleanup();
 1361      }
 1362    }
 1363
 1364    /// <summary>
 1365    /// Abort updating leaving the archive unchanged.
 1366    /// </summary>
 1367    /// <seealso cref="BeginUpdate()"></seealso>
 1368    /// <seealso cref="CommitUpdate"></seealso>
 1369    public void AbortUpdate()
 1370    {
 1371      PostUpdateCleanup();
 1372    }
 1373
 1374    /// <summary>
 1375    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.
 1376    /// </summary>
 1377    /// <param name="comment">The comment to record.</param>
 1378    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1379    public void SetComment(string comment)
 1380    {
 1381      if (isDisposed_) {
 1382        throw new ObjectDisposedException("ZipFile");
 1383      }
 1384
 1385      CheckUpdating();
 1386
 1387      newComment_ = new ZipString(comment);
 1388
 1389      if (newComment_.RawLength > 0xffff) {
 1390        newComment_ = null;
 1391        throw new ZipException("Comment length exceeds maximum - 65535");
 1392      }
 1393
 1394      // We dont take account of the original and current comment appearing to be the same
 1395      // as encoding may be different.
 1396      commentEdited_ = true;
 1397    }
 1398
 1399    #endregion
 1400
 1401    #region Adding Entries
 1402
 1403    void AddUpdate(ZipUpdate update)
 1404    {
 1405      contentsEdited_ = true;
 1406
 1407      int index = FindExistingUpdate(update.Entry.Name);
 1408
 1409      if (index >= 0) {
 1410        if (updates_[index] == null) {
 1411          updateCount_ += 1;
 1412        }
 1413
 1414        // Direct replacement is faster than delete and add.
 1415        updates_[index] = update;
 1416      } else {
 1417        index = updates_.Add(update);
 1418        updateCount_ += 1;
 1419        updateIndex_.Add(update.Entry.Name, index);
 1420      }
 1421    }
 1422
 1423    /// <summary>
 1424    /// Add a new entry to the archive.
 1425    /// </summary>
 1426    /// <param name="fileName">The name of the file to add.</param>
 1427    /// <param name="compressionMethod">The compression method to use.</param>
 1428    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>
 1429    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1430    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1431    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>
 1432    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText)
 1433    {
 1434      if (fileName == null) {
 1435        throw new ArgumentNullException(nameof(fileName));
 1436      }
 1437
 1438      if (isDisposed_) {
 1439        throw new ObjectDisposedException("ZipFile");
 1440      }
 1441
 1442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1444      }
 1445
 1446      CheckUpdating();
 1447      contentsEdited_ = true;
 1448
 1449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1450      entry.IsUnicodeText = useUnicodeText;
 1451      entry.CompressionMethod = compressionMethod;
 1452
 1453      AddUpdate(new ZipUpdate(fileName, entry));
 1454    }
 1455
 1456    /// <summary>
 1457    /// Add a new entry to the archive.
 1458    /// </summary>
 1459    /// <param name="fileName">The name of the file to add.</param>
 1460    /// <param name="compressionMethod">The compression method to use.</param>
 1461    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>
 1462    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>
 1463    public void Add(string fileName, CompressionMethod compressionMethod)
 1464    {
 1465      if (fileName == null) {
 1466        throw new ArgumentNullException(nameof(fileName));
 1467      }
 1468
 1469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1471      }
 1472
 1473      CheckUpdating();
 1474      contentsEdited_ = true;
 1475
 1476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1477      entry.CompressionMethod = compressionMethod;
 1478      AddUpdate(new ZipUpdate(fileName, entry));
 1479    }
 1480
 1481    /// <summary>
 1482    /// Add a file to the archive.
 1483    /// </summary>
 1484    /// <param name="fileName">The name of the file to add.</param>
 1485    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1486    public void Add(string fileName)
 1487    {
 1488      if (fileName == null) {
 1489        throw new ArgumentNullException(nameof(fileName));
 1490      }
 1491
 1492      CheckUpdating();
 1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));
 1494    }
 1495
 1496    /// <summary>
 1497    /// Add a file to the archive.
 1498    /// </summary>
 1499    /// <param name="fileName">The name of the file to add.</param>
 1500    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>
 1501    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1502    public void Add(string fileName, string entryName)
 1503    {
 1504      if (fileName == null) {
 1505        throw new ArgumentNullException(nameof(fileName));
 1506      }
 1507
 1508      if (entryName == null) {
 1509        throw new ArgumentNullException(nameof(entryName));
 1510      }
 1511
 1512      CheckUpdating();
 1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));
 1514    }
 1515
 1516
 1517    /// <summary>
 1518    /// Add a file entry with data.
 1519    /// </summary>
 1520    /// <param name="dataSource">The source of the data for this entry.</param>
 1521    /// <param name="entryName">The name to give to the entry.</param>
 1522    public void Add(IStaticDataSource dataSource, string entryName)
 1523    {
 1524      if (dataSource == null) {
 1525        throw new ArgumentNullException(nameof(dataSource));
 1526      }
 1527
 1528      if (entryName == null) {
 1529        throw new ArgumentNullException(nameof(entryName));
 1530      }
 1531
 1532      CheckUpdating();
 1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));
 1534    }
 1535
 1536    /// <summary>
 1537    /// Add a file entry with data.
 1538    /// </summary>
 1539    /// <param name="dataSource">The source of the data for this entry.</param>
 1540    /// <param name="entryName">The name to give to the entry.</param>
 1541    /// <param name="compressionMethod">The compression method to use.</param>
 1542    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 1543    {
 1544      if (dataSource == null) {
 1545        throw new ArgumentNullException(nameof(dataSource));
 1546      }
 1547
 1548      if (entryName == null) {
 1549        throw new ArgumentNullException(nameof(entryName));
 1550      }
 1551
 1552      CheckUpdating();
 1553
 1554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1555      entry.CompressionMethod = compressionMethod;
 1556
 1557      AddUpdate(new ZipUpdate(dataSource, entry));
 1558    }
 1559
 1560    /// <summary>
 1561    /// Add a file entry with data.
 1562    /// </summary>
 1563    /// <param name="dataSource">The source of the data for this entry.</param>
 1564    /// <param name="entryName">The name to give to the entry.</param>
 1565    /// <param name="compressionMethod">The compression method to use.</param>
 1566    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>
 1567    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode
 1568    {
 1569      if (dataSource == null) {
 1570        throw new ArgumentNullException(nameof(dataSource));
 1571      }
 1572
 1573      if (entryName == null) {
 1574        throw new ArgumentNullException(nameof(entryName));
 1575      }
 1576
 1577      CheckUpdating();
 1578
 1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1580      entry.IsUnicodeText = useUnicodeText;
 1581      entry.CompressionMethod = compressionMethod;
 1582
 1583      AddUpdate(new ZipUpdate(dataSource, entry));
 1584    }
 1585
 1586    /// <summary>
 1587    /// Add a <see cref="ZipEntry"/> that contains no data.
 1588    /// </summary>
 1589    /// <param name="entry">The entry to add.</param>
 1590    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
 1591    public void Add(ZipEntry entry)
 1592    {
 1593      if (entry == null) {
 1594        throw new ArgumentNullException(nameof(entry));
 1595      }
 1596
 1597      CheckUpdating();
 1598
 1599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {
 1600        throw new ZipException("Entry cannot have any data");
 1601      }
 1602
 1603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
 1604    }
 1605
 1606    /// <summary>
 1607    /// Add a directory entry to the archive.
 1608    /// </summary>
 1609    /// <param name="directoryName">The directory to add.</param>
 1610    public void AddDirectory(string directoryName)
 1611    {
 1612      if (directoryName == null) {
 1613        throw new ArgumentNullException(nameof(directoryName));
 1614      }
 1615
 1616      CheckUpdating();
 1617
 1618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);
 1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));
 1620    }
 1621
 1622    #endregion
 1623
 1624    #region Modifying Entries
 1625    /* Modify not yet ready for public consumption.
 1626       Direct modification of an entry should not overwrite original data before its read.
 1627       Safe mode is trivial in this sense.
 1628        public void Modify(ZipEntry original, ZipEntry updated)
 1629        {
 1630          if ( original == null ) {
 1631            throw new ArgumentNullException("original");
 1632          }
 1633
 1634          if ( updated == null ) {
 1635            throw new ArgumentNullException("updated");
 1636          }
 1637
 1638          CheckUpdating();
 1639          contentsEdited_ = true;
 1640          updates_.Add(new ZipUpdate(original, updated));
 1641        }
 1642    */
 1643    #endregion
 1644
 1645    #region Deleting Entries
 1646    /// <summary>
 1647    /// Delete an entry by name
 1648    /// </summary>
 1649    /// <param name="fileName">The filename to delete</param>
 1650    /// <returns>True if the entry was found and deleted; false otherwise.</returns>
 1651    public bool Delete(string fileName)
 1652    {
 1653      if (fileName == null) {
 1654        throw new ArgumentNullException(nameof(fileName));
 1655      }
 1656
 1657      CheckUpdating();
 1658
 1659      bool result = false;
 1660      int index = FindExistingUpdate(fileName);
 1661      if ((index >= 0) && (updates_[index] != null)) {
 1662        result = true;
 1663        contentsEdited_ = true;
 1664        updates_[index] = null;
 1665        updateCount_ -= 1;
 1666      } else {
 1667        throw new ZipException("Cannot find entry to delete");
 1668      }
 1669      return result;
 1670    }
 1671
 1672    /// <summary>
 1673    /// Delete a <see cref="ZipEntry"/> from the archive.
 1674    /// </summary>
 1675    /// <param name="entry">The entry to delete.</param>
 1676    public void Delete(ZipEntry entry)
 1677    {
 1678      if (entry == null) {
 1679        throw new ArgumentNullException(nameof(entry));
 1680      }
 1681
 1682      CheckUpdating();
 1683
 1684      int index = FindExistingUpdate(entry);
 1685      if (index >= 0) {
 1686        contentsEdited_ = true;
 1687        updates_[index] = null;
 1688        updateCount_ -= 1;
 1689      } else {
 1690        throw new ZipException("Cannot find entry to delete");
 1691      }
 1692    }
 1693
 1694    #endregion
 1695
 1696    #region Update Support
 1697
 1698    #region Writing Values/Headers
 1699    void WriteLEShort(int value)
 1700    {
 1701      baseStream_.WriteByte((byte)(value & 0xff));
 1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));
 1703    }
 1704
 1705    /// <summary>
 1706    /// Write an unsigned short in little endian byte order.
 1707    /// </summary>
 1708    void WriteLEUshort(ushort value)
 1709    {
 1710      baseStream_.WriteByte((byte)(value & 0xff));
 1711      baseStream_.WriteByte((byte)(value >> 8));
 1712    }
 1713
 1714    /// <summary>
 1715    /// Write an int in little endian byte order.
 1716    /// </summary>
 1717    void WriteLEInt(int value)
 1718    {
 1719      WriteLEShort(value & 0xffff);
 1720      WriteLEShort(value >> 16);
 1721    }
 1722
 1723    /// <summary>
 1724    /// Write an unsigned int in little endian byte order.
 1725    /// </summary>
 1726    void WriteLEUint(uint value)
 1727    {
 1728      WriteLEUshort((ushort)(value & 0xffff));
 1729      WriteLEUshort((ushort)(value >> 16));
 1730    }
 1731
 1732    /// <summary>
 1733    /// Write a long in little endian byte order.
 1734    /// </summary>
 1735    void WriteLeLong(long value)
 1736    {
 1737      WriteLEInt((int)(value & 0xffffffff));
 1738      WriteLEInt((int)(value >> 32));
 1739    }
 1740
 1741    void WriteLEUlong(ulong value)
 1742    {
 1743      WriteLEUint((uint)(value & 0xffffffff));
 1744      WriteLEUint((uint)(value >> 32));
 1745    }
 1746
 1747    void WriteLocalEntryHeader(ZipUpdate update)
 1748    {
 1749      ZipEntry entry = update.OutEntry;
 1750
 1751      // TODO: Local offset will require adjusting for multi-disk zip files.
 1752      entry.Offset = baseStream_.Position;
 1753
 1754      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
 1755      if (update.Command != UpdateCommand.Copy) {
 1756        if (entry.CompressionMethod == CompressionMethod.Deflated) {
 1757          if (entry.Size == 0) {
 1758            // No need to compress - no data.
 1759            entry.CompressedSize = entry.Size;
 1760            entry.Crc = 0;
 1761            entry.CompressionMethod = CompressionMethod.Stored;
 1762          }
 1763        } else if (entry.CompressionMethod == CompressionMethod.Stored) {
 1764          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
 1765        }
 1766
 1767        if (HaveKeys) {
 1768          entry.IsCrypted = true;
 1769          if (entry.Crc < 0) {
 1770            entry.Flags |= (int)GeneralBitFlags.Descriptor;
 1771          }
 1772        } else {
 1773          entry.IsCrypted = false;
 1774        }
 1775
 1776        switch (useZip64_) {
 1777          case UseZip64.Dynamic:
 1778            if (entry.Size < 0) {
 1779              entry.ForceZip64();
 1780            }
 1781            break;
 1782
 1783          case UseZip64.On:
 1784            entry.ForceZip64();
 1785            break;
 1786
 1787          case UseZip64.Off:
 1788            // Do nothing.  The entry itself may be using Zip64 independantly.
 1789            break;
 1790        }
 1791      }
 1792
 1793      // Write the local file header
 1794      WriteLEInt(ZipConstants.LocalHeaderSignature);
 1795
 1796      WriteLEShort(entry.Version);
 1797      WriteLEShort(entry.Flags);
 1798
 1799      WriteLEShort((byte)entry.CompressionMethod);
 1800      WriteLEInt((int)entry.DosTime);
 1801
 1802      if (!entry.HasCrc) {
 1803        // Note patch address for updating CRC later.
 1804        update.CrcPatchOffset = baseStream_.Position;
 1805        WriteLEInt((int)0);
 1806      } else {
 1807        WriteLEInt(unchecked((int)entry.Crc));
 1808      }
 1809
 1810      if (entry.LocalHeaderRequiresZip64) {
 1811        WriteLEInt(-1);
 1812        WriteLEInt(-1);
 1813      } else {
 1814        if ((entry.CompressedSize < 0) || (entry.Size < 0)) {
 1815          update.SizePatchOffset = baseStream_.Position;
 1816        }
 1817
 1818        WriteLEInt((int)entry.CompressedSize);
 1819        WriteLEInt((int)entry.Size);
 1820      }
 1821
 1822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1823
 1824      if (name.Length > 0xFFFF) {
 1825        throw new ZipException("Entry name too long.");
 1826      }
 1827
 1828      var ed = new ZipExtraData(entry.ExtraData);
 1829
 1830      if (entry.LocalHeaderRequiresZip64) {
 1831        ed.StartNewEntry();
 1832
 1833        // Local entry header always includes size and compressed size.
 1834        // NOTE the order of these fields is reversed when compared to the normal headers!
 1835        ed.AddLeLong(entry.Size);
 1836        ed.AddLeLong(entry.CompressedSize);
 1837        ed.AddNewEntry(1);
 1838      } else {
 1839        ed.Delete(1);
 1840      }
 1841
 1842      entry.ExtraData = ed.GetEntryData();
 1843
 1844      WriteLEShort(name.Length);
 1845      WriteLEShort(entry.ExtraData.Length);
 1846
 1847      if (name.Length > 0) {
 1848        baseStream_.Write(name, 0, name.Length);
 1849      }
 1850
 1851      if (entry.LocalHeaderRequiresZip64) {
 1852        if (!ed.Find(1)) {
 1853          throw new ZipException("Internal error cannot find extra data");
 1854        }
 1855
 1856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
 1857      }
 1858
 1859      if (entry.ExtraData.Length > 0) {
 1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
 1861      }
 1862    }
 1863
 1864    int WriteCentralDirectoryHeader(ZipEntry entry)
 1865    {
 1866      if (entry.CompressedSize < 0) {
 1867        throw new ZipException("Attempt to write central directory entry with unknown csize");
 1868      }
 1869
 1870      if (entry.Size < 0) {
 1871        throw new ZipException("Attempt to write central directory entry with unknown size");
 1872      }
 1873
 1874      if (entry.Crc < 0) {
 1875        throw new ZipException("Attempt to write central directory entry with unknown crc");
 1876      }
 1877
 1878      // Write the central file header
 1879      WriteLEInt(ZipConstants.CentralHeaderSignature);
 1880
 1881      // Version made by
 1882      WriteLEShort(ZipConstants.VersionMadeBy);
 1883
 1884      // Version required to extract
 1885      WriteLEShort(entry.Version);
 1886
 1887      WriteLEShort(entry.Flags);
 1888
 1889      unchecked {
 1890        WriteLEShort((byte)entry.CompressionMethod);
 1891        WriteLEInt((int)entry.DosTime);
 1892        WriteLEInt((int)entry.Crc);
 1893      }
 1894
 1895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {
 1896        WriteLEInt(-1);
 1897      } else {
 1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
 1899      }
 1900
 1901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {
 1902        WriteLEInt(-1);
 1903      } else {
 1904        WriteLEInt((int)entry.Size);
 1905      }
 1906
 1907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1908
 1909      if (name.Length > 0xFFFF) {
 1910        throw new ZipException("Entry name is too long.");
 1911      }
 1912
 1913      WriteLEShort(name.Length);
 1914
 1915      // Central header extra data is different to local header version so regenerate.
 1916      var ed = new ZipExtraData(entry.ExtraData);
 1917
 1918      if (entry.CentralHeaderRequiresZip64) {
 1919        ed.StartNewEntry();
 1920
 1921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1922          ed.AddLeLong(entry.Size);
 1923        }
 1924
 1925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1926          ed.AddLeLong(entry.CompressedSize);
 1927        }
 1928
 1929        if (entry.Offset >= 0xffffffff) {
 1930          ed.AddLeLong(entry.Offset);
 1931        }
 1932
 1933        // Number of disk on which this file starts isnt supported and is never written here.
 1934        ed.AddNewEntry(1);
 1935      } else {
 1936        // Should have already be done when local header was added.
 1937        ed.Delete(1);
 1938      }
 1939
 1940      byte[] centralExtraData = ed.GetEntryData();
 1941
 1942      WriteLEShort(centralExtraData.Length);
 1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);
 1944
 1945      WriteLEShort(0);    // disk number
 1946      WriteLEShort(0);    // internal file attributes
 1947
 1948      // External file attributes...
 1949      if (entry.ExternalFileAttributes != -1) {
 1950        WriteLEInt(entry.ExternalFileAttributes);
 1951      } else {
 1952        if (entry.IsDirectory) {
 1953          WriteLEUint(16);
 1954        } else {
 1955          WriteLEUint(0);
 1956        }
 1957      }
 1958
 1959      if (entry.Offset >= 0xffffffff) {
 1960        WriteLEUint(0xffffffff);
 1961      } else {
 1962        WriteLEUint((uint)(int)entry.Offset);
 1963      }
 1964
 1965      if (name.Length > 0) {
 1966        baseStream_.Write(name, 0, name.Length);
 1967      }
 1968
 1969      if (centralExtraData.Length > 0) {
 1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
 1971      }
 1972
 1973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];
 1974
 1975      if (rawComment.Length > 0) {
 1976        baseStream_.Write(rawComment, 0, rawComment.Length);
 1977      }
 1978
 1979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
 1980    }
 1981    #endregion
 1982
 1983    void PostUpdateCleanup()
 1984    {
 1985      updateDataSource_ = null;
 1986      updates_ = null;
 1987      updateIndex_ = null;
 1988
 1989      if (archiveStorage_ != null) {
 1990        archiveStorage_.Dispose();
 1991        archiveStorage_ = null;
 1992      }
 1993    }
 1994
 1995    string GetTransformedFileName(string name)
 1996    {
 1997      INameTransform transform = NameTransform;
 1998      return (transform != null) ?
 1999        transform.TransformFile(name) :
 2000        name;
 2001    }
 2002
 2003    string GetTransformedDirectoryName(string name)
 2004    {
 2005      INameTransform transform = NameTransform;
 2006      return (transform != null) ?
 2007        transform.TransformDirectory(name) :
 2008        name;
 2009    }
 2010
 2011    /// <summary>
 2012    /// Get a raw memory buffer.
 2013    /// </summary>
 2014    /// <returns>Returns a raw memory buffer.</returns>
 2015    byte[] GetBuffer()
 2016    {
 2017      if (copyBuffer_ == null) {
 2018        copyBuffer_ = new byte[bufferSize_];
 2019      }
 2020      return copyBuffer_;
 2021    }
 2022
 2023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)
 2024    {
 2025      int bytesToCopy = GetDescriptorSize(update);
 2026
 2027      if (bytesToCopy > 0) {
 2028        byte[] buffer = GetBuffer();
 2029
 2030        while (bytesToCopy > 0) {
 2031          int readSize = Math.Min(buffer.Length, bytesToCopy);
 2032
 2033          int bytesRead = source.Read(buffer, 0, readSize);
 2034          if (bytesRead > 0) {
 2035            dest.Write(buffer, 0, bytesRead);
 2036            bytesToCopy -= bytesRead;
 2037          } else {
 2038            throw new ZipException("Unxpected end of stream");
 2039          }
 2040        }
 2041      }
 2042    }
 2043
 2044    void CopyBytes(ZipUpdate update, Stream destination, Stream source,
 2045      long bytesToCopy, bool updateCrc)
 2046    {
 2047      if (destination == source) {
 2048        throw new InvalidOperationException("Destination and source are the same");
 2049      }
 2050
 2051      // NOTE: Compressed size is updated elsewhere.
 2052      var crc = new Crc32();
 2053      byte[] buffer = GetBuffer();
 2054
 2055      long targetBytes = bytesToCopy;
 2056      long totalBytesRead = 0;
 2057
 2058      int bytesRead;
 2059      do {
 2060        int readSize = buffer.Length;
 2061
 2062        if (bytesToCopy < readSize) {
 2063          readSize = (int)bytesToCopy;
 2064        }
 2065
 2066        bytesRead = source.Read(buffer, 0, readSize);
 2067        if (bytesRead > 0) {
 2068          if (updateCrc) {
 2069            crc.Update(buffer, 0, bytesRead);
 2070          }
 2071          destination.Write(buffer, 0, bytesRead);
 2072          bytesToCopy -= bytesRead;
 2073          totalBytesRead += bytesRead;
 2074        }
 2075      }
 2076      while ((bytesRead > 0) && (bytesToCopy > 0));
 2077
 2078      if (totalBytesRead != targetBytes) {
 2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2080      }
 2081
 2082      if (updateCrc) {
 2083        update.OutEntry.Crc = crc.Value;
 2084      }
 2085    }
 2086
 2087    /// <summary>
 2088    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
 2089    /// </summary>
 2090    /// <param name="update">The update to get the size for.</param>
 2091    /// <returns>The descriptor size, zero if there isnt one.</returns>
 2092    int GetDescriptorSize(ZipUpdate update)
 2093    {
 2094      int result = 0;
 2095      if ((update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 2096        result = ZipConstants.DataDescriptorSize - 4;
 2097        if (update.Entry.LocalHeaderRequiresZip64) {
 2098          result = ZipConstants.Zip64DataDescriptorSize - 4;
 2099        }
 2100      }
 2101      return result;
 2102    }
 2103
 2104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
 2105    {
 2106      int bytesToCopy = GetDescriptorSize(update);
 2107
 2108      while (bytesToCopy > 0) {
 2109        var readSize = (int)bytesToCopy;
 2110        byte[] buffer = GetBuffer();
 2111
 2112        stream.Position = sourcePosition;
 2113        int bytesRead = stream.Read(buffer, 0, readSize);
 2114        if (bytesRead > 0) {
 2115          stream.Position = destinationPosition;
 2116          stream.Write(buffer, 0, bytesRead);
 2117          bytesToCopy -= bytesRead;
 2118          destinationPosition += bytesRead;
 2119          sourcePosition += bytesRead;
 2120        } else {
 2121          throw new ZipException("Unxpected end of stream");
 2122        }
 2123      }
 2124    }
 2125
 2126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou
 2127    {
 2128      long bytesToCopy = update.Entry.CompressedSize;
 2129
 2130      // NOTE: Compressed size is updated elsewhere.
 2131      var crc = new Crc32();
 2132      byte[] buffer = GetBuffer();
 2133
 2134      long targetBytes = bytesToCopy;
 2135      long totalBytesRead = 0;
 2136
 2137      int bytesRead;
 2138      do {
 2139        int readSize = buffer.Length;
 2140
 2141        if (bytesToCopy < readSize) {
 2142          readSize = (int)bytesToCopy;
 2143        }
 2144
 2145        stream.Position = sourcePosition;
 2146        bytesRead = stream.Read(buffer, 0, readSize);
 2147        if (bytesRead > 0) {
 2148          if (updateCrc) {
 2149            crc.Update(buffer, 0, bytesRead);
 2150          }
 2151          stream.Position = destinationPosition;
 2152          stream.Write(buffer, 0, bytesRead);
 2153
 2154          destinationPosition += bytesRead;
 2155          sourcePosition += bytesRead;
 2156          bytesToCopy -= bytesRead;
 2157          totalBytesRead += bytesRead;
 2158        }
 2159      }
 2160      while ((bytesRead > 0) && (bytesToCopy > 0));
 2161
 2162      if (totalBytesRead != targetBytes) {
 2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2164      }
 2165
 2166      if (updateCrc) {
 2167        update.OutEntry.Crc = crc.Value;
 2168      }
 2169    }
 2170
 2171    int FindExistingUpdate(ZipEntry entry)
 2172    {
 2173      int result = -1;
 2174      string convertedName = GetTransformedFileName(entry.Name);
 2175
 2176      if (updateIndex_.ContainsKey(convertedName)) {
 2177        result = (int)updateIndex_[convertedName];
 2178      }
 2179      /*
 2180            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2181            // for CF?
 2182            for (int index = 0; index < updates_.Count; ++index)
 2183            {
 2184              ZipUpdate zu = ( ZipUpdate )updates_[index];
 2185              if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
 2186                (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
 2187                result = index;
 2188                break;
 2189              }
 2190            }
 2191       */
 2192      return result;
 2193    }
 2194
 2195    int FindExistingUpdate(string fileName)
 2196    {
 2197      int result = -1;
 2198
 2199      string convertedName = GetTransformedFileName(fileName);
 2200
 2201      if (updateIndex_.ContainsKey(convertedName)) {
 2202        result = (int)updateIndex_[convertedName];
 2203      }
 2204
 2205      /*
 2206            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2207            // for CF?
 2208            for ( int index = 0; index < updates_.Count; ++index ) {
 2209              if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,
 2210                true, CultureInfo.InvariantCulture) == 0 ) {
 2211                result = index;
 2212                break;
 2213              }
 2214            }
 2215       */
 2216
 2217      return result;
 2218    }
 2219
 2220    /// <summary>
 2221    /// Get an output stream for the specified <see cref="ZipEntry"/>
 2222    /// </summary>
 2223    /// <param name="entry">The entry to get an output stream for.</param>
 2224    /// <returns>The output stream obtained for the entry.</returns>
 2225    Stream GetOutputStream(ZipEntry entry)
 2226    {
 2227      Stream result = baseStream_;
 2228
 2229      if (entry.IsCrypted == true) {
 2230        result = CreateAndInitEncryptionStream(result, entry);
 2231      }
 2232
 2233      switch (entry.CompressionMethod) {
 2234        case CompressionMethod.Stored:
 2235          result = new UncompressedStream(result);
 2236          break;
 2237
 2238        case CompressionMethod.Deflated:
 2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));
 2240          dos.IsStreamOwner = false;
 2241          result = dos;
 2242          break;
 2243
 2244        default:
 2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);
 2246      }
 2247      return result;
 2248    }
 2249
 2250    void AddEntry(ZipFile workFile, ZipUpdate update)
 2251    {
 2252      Stream source = null;
 2253
 2254      if (update.Entry.IsFile) {
 2255        source = update.GetSource();
 2256
 2257        if (source == null) {
 2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);
 2259        }
 2260      }
 2261
 2262      if (source != null) {
 2263        using (source) {
 2264          long sourceStreamLength = source.Length;
 2265          if (update.OutEntry.Size < 0) {
 2266            update.OutEntry.Size = sourceStreamLength;
 2267          } else {
 2268            // Check for errant entries.
 2269            if (update.OutEntry.Size != sourceStreamLength) {
 2270              throw new ZipException("Entry size/stream size mismatch");
 2271            }
 2272          }
 2273
 2274          workFile.WriteLocalEntryHeader(update);
 2275
 2276          long dataStart = workFile.baseStream_.Position;
 2277
 2278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2279            CopyBytes(update, output, source, sourceStreamLength, true);
 2280          }
 2281
 2282          long dataEnd = workFile.baseStream_.Position;
 2283          update.OutEntry.CompressedSize = dataEnd - dataStart;
 2284
 2285          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor) {
 2286            var helper = new ZipHelperStream(workFile.baseStream_);
 2287            helper.WriteDataDescriptor(update.OutEntry);
 2288          }
 2289        }
 2290      } else {
 2291        workFile.WriteLocalEntryHeader(update);
 2292        update.OutEntry.CompressedSize = 0;
 2293      }
 2294
 2295    }
 2296
 2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)
 2298    {
 2299      workFile.WriteLocalEntryHeader(update);
 2300      long dataStart = workFile.baseStream_.Position;
 2301
 2302      // TODO: This is slow if the changes don't effect the data!!
 2303      if (update.Entry.IsFile && (update.Filename != null)) {
 2304        using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2305          using (Stream source = this.GetInputStream(update.Entry)) {
 2306            CopyBytes(update, output, source, source.Length, true);
 2307          }
 2308        }
 2309      }
 2310
 2311      long dataEnd = workFile.baseStream_.Position;
 2312      update.Entry.CompressedSize = dataEnd - dataStart;
 2313    }
 2314
 2315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)
 2316    {
 2317      bool skipOver = false || update.Entry.Offset == destinationPosition;
 2318
 2319      if (!skipOver) {
 2320        baseStream_.Position = destinationPosition;
 2321        workFile.WriteLocalEntryHeader(update);
 2322        destinationPosition = baseStream_.Position;
 2323      }
 2324
 2325      long sourcePosition = 0;
 2326
 2327      const int NameLengthOffset = 26;
 2328
 2329      // TODO: Add base for SFX friendly handling
 2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2331
 2332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2333
 2334      // Clumsy way of handling retrieving the original name and extra data length for now.
 2335      // TODO: Stop re-reading name and data length in CopyEntryDirect.
 2336      uint nameLength = ReadLEUshort();
 2337      uint extraLength = ReadLEUshort();
 2338
 2339      sourcePosition = baseStream_.Position + nameLength + extraLength;
 2340
 2341      if (skipOver) {
 2342        if (update.OffsetBasedSize != -1)
 2343          destinationPosition += update.OffsetBasedSize;
 2344        else
 2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar
 2346          // WinZip produces a warning on these entries:
 2347          // "caution: value of lrec.csize (compressed size) changed from ..."
 2348          destinationPosition +=
 2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size
 2350            update.Entry.CompressedSize + GetDescriptorSize(update);
 2351      } else {
 2352        if (update.Entry.CompressedSize > 0) {
 2353          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition);
 2354        }
 2355        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
 2356      }
 2357    }
 2358
 2359    void CopyEntry(ZipFile workFile, ZipUpdate update)
 2360    {
 2361      workFile.WriteLocalEntryHeader(update);
 2362
 2363      if (update.Entry.CompressedSize > 0) {
 2364        const int NameLengthOffset = 26;
 2365
 2366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2367
 2368        // TODO: This wont work for SFX files!
 2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2370
 2371        uint nameLength = ReadLEUshort();
 2372        uint extraLength = ReadLEUshort();
 2373
 2374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);
 2375
 2376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
 2377      }
 2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
 2379    }
 2380
 2381    void Reopen(Stream source)
 2382    {
 2383      if (source == null) {
 2384        throw new ZipException("Failed to reopen archive - no source");
 2385      }
 2386
 2387      isNewArchive_ = false;
 2388      baseStream_ = source;
 2389      ReadEntries();
 2390    }
 2391
 2392    void Reopen()
 2393    {
 2394      if (Name == null) {
 2395        throw new InvalidOperationException("Name is not known cannot Reopen");
 2396      }
 2397
 2398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));
 2399    }
 2400
 2401    void UpdateCommentOnly()
 2402    {
 2403      long baseLength = baseStream_.Length;
 2404
 2405      ZipHelperStream updateFile = null;
 2406
 2407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
 2409        updateFile = new ZipHelperStream(copyStream);
 2410        updateFile.IsStreamOwner = true;
 2411
 2412        baseStream_.Close();
 2413        baseStream_ = null;
 2414      } else {
 2415        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2416          // TODO: archiveStorage wasnt originally intended for this use.
 2417          // Need to revisit this to tidy up handling as archive storage currently doesnt
 2418          // handle the original stream well.
 2419          // The problem is when using an existing zip archive with an in memory archive storage.
 2420          // The open stream wont support writing but the memory storage should open the same file not an in memory one.
 2421
 2422          // Need to tidy up the archive storage interface and contract basically.
 2423          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);
 2424          updateFile = new ZipHelperStream(baseStream_);
 2425        } else {
 2426          baseStream_.Close();
 2427          baseStream_ = null;
 2428          updateFile = new ZipHelperStream(Name);
 2429        }
 2430      }
 2431
 2432      using (updateFile) {
 2433        long locatedCentralDirOffset =
 2434          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2435                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2436        if (locatedCentralDirOffset < 0) {
 2437          throw new ZipException("Cannot find central directory");
 2438        }
 2439
 2440        const int CentralHeaderCommentSizeOffset = 16;
 2441        updateFile.Position += CentralHeaderCommentSizeOffset;
 2442
 2443        byte[] rawComment = newComment_.RawComment;
 2444
 2445        updateFile.WriteLEShort(rawComment.Length);
 2446        updateFile.Write(rawComment, 0, rawComment.Length);
 2447        updateFile.SetLength(updateFile.Position);
 2448      }
 2449
 2450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2452      } else {
 2453        ReadEntries();
 2454      }
 2455    }
 2456
 2457    /// <summary>
 2458    /// Class used to sort updates.
 2459    /// </summary>
 2460    class UpdateComparer : IComparer
 2461    {
 2462      /// <summary>
 2463      /// Compares two objects and returns a value indicating whether one is
 2464      /// less than, equal to or greater than the other.
 2465      /// </summary>
 2466      /// <param name="x">First object to compare</param>
 2467      /// <param name="y">Second object to compare.</param>
 2468      /// <returns>Compare result.</returns>
 2469      public int Compare(
 2470        object x,
 2471        object y)
 2472      {
 2473        var zx = x as ZipUpdate;
 2474        var zy = y as ZipUpdate;
 2475
 2476        int result;
 2477
 2478        if (zx == null) {
 2479          if (zy == null) {
 2480            result = 0;
 2481          } else {
 2482            result = -1;
 2483          }
 2484        } else if (zy == null) {
 2485          result = 1;
 2486        } else {
 2487          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;
 2488          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;
 2489
 2490          result = xCmdValue - yCmdValue;
 2491          if (result == 0) {
 2492            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;
 2493            if (offsetDiff < 0) {
 2494              result = -1;
 2495            } else if (offsetDiff == 0) {
 2496              result = 0;
 2497            } else {
 2498              result = 1;
 2499            }
 2500          }
 2501        }
 2502        return result;
 2503      }
 2504    }
 2505
 2506    void RunUpdates()
 2507    {
 2508      long sizeEntries = 0;
 2509      long endOfStream = 0;
 2510      bool directUpdate = false;
 2511      long destinationPosition = 0; // NOT SFX friendly
 2512
 2513      ZipFile workFile;
 2514
 2515      if (IsNewArchive) {
 2516        workFile = this;
 2517        workFile.baseStream_.Position = 0;
 2518        directUpdate = true;
 2519      } else if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2520        workFile = this;
 2521        workFile.baseStream_.Position = 0;
 2522        directUpdate = true;
 2523
 2524        // Sort the updates by offset within copies/modifies, then adds.
 2525        // This ensures that data required by copies will not be overwritten.
 2526        updates_.Sort(new UpdateComparer());
 2527      } else {
 2528        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
 2529        workFile.UseZip64 = UseZip64;
 2530
 2531        if (key != null) {
 2532          workFile.key = (byte[])key.Clone();
 2533        }
 2534      }
 2535
 2536      try {
 2537        foreach (ZipUpdate update in updates_) {
 2538          if (update != null) {
 2539            switch (update.Command) {
 2540              case UpdateCommand.Copy:
 2541                if (directUpdate) {
 2542                  CopyEntryDirect(workFile, update, ref destinationPosition);
 2543                } else {
 2544                  CopyEntry(workFile, update);
 2545                }
 2546                break;
 2547
 2548              case UpdateCommand.Modify:
 2549                // TODO: Direct modifying of an entry will take some legwork.
 2550                ModifyEntry(workFile, update);
 2551                break;
 2552
 2553              case UpdateCommand.Add:
 2554                if (!IsNewArchive && directUpdate) {
 2555                  workFile.baseStream_.Position = destinationPosition;
 2556                }
 2557
 2558                AddEntry(workFile, update);
 2559
 2560                if (directUpdate) {
 2561                  destinationPosition = workFile.baseStream_.Position;
 2562                }
 2563                break;
 2564            }
 2565          }
 2566        }
 2567
 2568        if (!IsNewArchive && directUpdate) {
 2569          workFile.baseStream_.Position = destinationPosition;
 2570        }
 2571
 2572        long centralDirOffset = workFile.baseStream_.Position;
 2573
 2574        foreach (ZipUpdate update in updates_) {
 2575          if (update != null) {
 2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
 2577          }
 2578        }
 2579
 2580        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 2581        using (ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_)) {
 2582          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);
 2583        }
 2584
 2585        endOfStream = workFile.baseStream_.Position;
 2586
 2587        // And now patch entries...
 2588        foreach (ZipUpdate update in updates_) {
 2589          if (update != null) {
 2590            // If the size of the entry is zero leave the crc as 0 as well.
 2591            // The calculated crc will be all bits on...
 2592            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {
 2593              workFile.baseStream_.Position = update.CrcPatchOffset;
 2594              workFile.WriteLEInt((int)update.OutEntry.Crc);
 2595            }
 2596
 2597            if (update.SizePatchOffset > 0) {
 2598              workFile.baseStream_.Position = update.SizePatchOffset;
 2599              if (update.OutEntry.LocalHeaderRequiresZip64) {
 2600                workFile.WriteLeLong(update.OutEntry.Size);
 2601                workFile.WriteLeLong(update.OutEntry.CompressedSize);
 2602              } else {
 2603                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);
 2604                workFile.WriteLEInt((int)update.OutEntry.Size);
 2605              }
 2606            }
 2607          }
 2608        }
 2609      } catch {
 2610        workFile.Close();
 2611        if (!directUpdate && (workFile.Name != null)) {
 2612          File.Delete(workFile.Name);
 2613        }
 2614        throw;
 2615      }
 2616
 2617      if (directUpdate) {
 2618        workFile.baseStream_.SetLength(endOfStream);
 2619        workFile.baseStream_.Flush();
 2620        isNewArchive_ = false;
 2621        ReadEntries();
 2622      } else {
 2623        baseStream_.Close();
 2624        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2625      }
 2626    }
 2627
 2628    void CheckUpdating()
 2629    {
 2630      if (updates_ == null) {
 2631        throw new InvalidOperationException("BeginUpdate has not been called");
 2632      }
 2633    }
 2634
 2635    #endregion
 2636
 2637    #region ZipUpdate class
 2638    /// <summary>
 2639    /// Represents a pending update to a Zip file.
 2640    /// </summary>
 2641    class ZipUpdate
 2642    {
 2643      #region Constructors
 2644      public ZipUpdate(string fileName, ZipEntry entry)
 2645      {
 2646        command_ = UpdateCommand.Add;
 2647        entry_ = entry;
 2648        filename_ = fileName;
 2649      }
 2650
 2651      [Obsolete]
 2652      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 2653      {
 2654        command_ = UpdateCommand.Add;
 2655        entry_ = new ZipEntry(entryName);
 2656        entry_.CompressionMethod = compressionMethod;
 2657        filename_ = fileName;
 2658      }
 2659
 2660      [Obsolete]
 2661      public ZipUpdate(string fileName, string entryName)
 2662        : this(fileName, entryName, CompressionMethod.Deflated)
 2663      {
 2664        // Do nothing.
 2665      }
 2666
 2667      [Obsolete]
 2668      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 2669      {
 2670        command_ = UpdateCommand.Add;
 2671        entry_ = new ZipEntry(entryName);
 2672        entry_.CompressionMethod = compressionMethod;
 2673        dataSource_ = dataSource;
 2674      }
 2675
 2676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 2677      {
 2678        command_ = UpdateCommand.Add;
 2679        entry_ = entry;
 2680        dataSource_ = dataSource;
 2681      }
 2682
 2683      public ZipUpdate(ZipEntry original, ZipEntry updated)
 2684      {
 2685        throw new ZipException("Modify not currently supported");
 2686        /*
 2687          command_ = UpdateCommand.Modify;
 2688          entry_ = ( ZipEntry )original.Clone();
 2689          outEntry_ = ( ZipEntry )updated.Clone();
 2690        */
 2691      }
 2692
 2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)
 2694      {
 2695        command_ = command;
 2696        entry_ = (ZipEntry)entry.Clone();
 2697      }
 2698
 2699
 2700      /// <summary>
 2701      /// Copy an existing entry.
 2702      /// </summary>
 2703      /// <param name="entry">The existing entry to copy.</param>
 2704      public ZipUpdate(ZipEntry entry)
 2705        : this(UpdateCommand.Copy, entry)
 2706      {
 2707        // Do nothing.
 2708      }
 2709      #endregion
 2710
 2711      /// <summary>
 2712      /// Get the <see cref="ZipEntry"/> for this update.
 2713      /// </summary>
 2714      /// <remarks>This is the source or original entry.</remarks>
 2715      public ZipEntry Entry {
 2716        get { return entry_; }
 2717      }
 2718
 2719      /// <summary>
 2720      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.
 2721      /// </summary>
 2722      public ZipEntry OutEntry {
 2723        get {
 2724          if (outEntry_ == null) {
 2725            outEntry_ = (ZipEntry)entry_.Clone();
 2726          }
 2727
 2728          return outEntry_;
 2729        }
 2730      }
 2731
 2732      /// <summary>
 2733      /// Get the command for this update.
 2734      /// </summary>
 2735      public UpdateCommand Command {
 2736        get { return command_; }
 2737      }
 2738
 2739      /// <summary>
 2740      /// Get the filename if any for this update.  Null if none exists.
 2741      /// </summary>
 2742      public string Filename {
 2743        get { return filename_; }
 2744      }
 2745
 2746      /// <summary>
 2747      /// Get/set the location of the size patch for this update.
 2748      /// </summary>
 2749      public long SizePatchOffset {
 2750        get { return sizePatchOffset_; }
 2751        set { sizePatchOffset_ = value; }
 2752      }
 2753
 2754      /// <summary>
 2755      /// Get /set the location of the crc patch for this update.
 2756      /// </summary>
 2757      public long CrcPatchOffset {
 2758        get { return crcPatchOffset_; }
 2759        set { crcPatchOffset_ = value; }
 2760      }
 2761
 2762      /// <summary>
 2763      /// Get/set the size calculated by offset.
 2764      /// Specifically, the difference between this and next entry's starting offset.
 2765      /// </summary>
 2766      public long OffsetBasedSize {
 2767        get { return _offsetBasedSize; }
 2768        set { _offsetBasedSize = value; }
 2769      }
 2770
 2771      public Stream GetSource()
 2772      {
 2773        Stream result = null;
 2774        if (dataSource_ != null) {
 2775          result = dataSource_.GetSource();
 2776        }
 2777
 2778        return result;
 2779      }
 2780
 2781      #region Instance Fields
 2782      ZipEntry entry_;
 2783      ZipEntry outEntry_;
 2784      UpdateCommand command_;
 2785      IStaticDataSource dataSource_;
 2786      string filename_;
 2787      long sizePatchOffset_ = -1;
 2788      long crcPatchOffset_ = -1;
 2789      long _offsetBasedSize = -1;
 2790      #endregion
 2791    }
 2792
 2793    #endregion
 2794    #endregion
 2795
 2796    #region Disposing
 2797
 2798    #region IDisposable Members
 2799    void IDisposable.Dispose()
 2800    {
 2801      Close();
 2802    }
 2803    #endregion
 2804
 2805    void DisposeInternal(bool disposing)
 2806    {
 2807      if (!isDisposed_) {
 2808        isDisposed_ = true;
 2809        entries_ = new ZipEntry[0];
 2810
 2811        if (IsStreamOwner && (baseStream_ != null)) {
 2812          lock (baseStream_) {
 2813            baseStream_.Close();
 2814          }
 2815        }
 2816
 2817        PostUpdateCleanup();
 2818      }
 2819    }
 2820
 2821    /// <summary>
 2822    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.
 2823    /// </summary>
 2824    /// <param name="disposing">true to release both managed and unmanaged resources;
 2825    /// false to release only unmanaged resources.</param>
 2826    protected virtual void Dispose(bool disposing)
 2827    {
 2828      DisposeInternal(disposing);
 2829    }
 2830
 2831    #endregion
 2832
 2833    #region Internal routines
 2834    #region Reading
 2835    /// <summary>
 2836    /// Read an unsigned short in little endian byte order.
 2837    /// </summary>
 2838    /// <returns>Returns the value read.</returns>
 2839    /// <exception cref="EndOfStreamException">
 2840    /// The stream ends prematurely
 2841    /// </exception>
 2842    ushort ReadLEUshort()
 2843    {
 2844      int data1 = baseStream_.ReadByte();
 2845
 2846      if (data1 < 0) {
 2847        throw new EndOfStreamException("End of stream");
 2848      }
 2849
 2850      int data2 = baseStream_.ReadByte();
 2851
 2852      if (data2 < 0) {
 2853        throw new EndOfStreamException("End of stream");
 2854      }
 2855
 2856
 2857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));
 2858    }
 2859
 2860    /// <summary>
 2861    /// Read a uint in little endian byte order.
 2862    /// </summary>
 2863    /// <returns>Returns the value read.</returns>
 2864    /// <exception cref="IOException">
 2865    /// An i/o error occurs.
 2866    /// </exception>
 2867    /// <exception cref="System.IO.EndOfStreamException">
 2868    /// The file ends prematurely
 2869    /// </exception>
 2870    uint ReadLEUint()
 2871    {
 2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));
 2873    }
 2874
 2875    ulong ReadLEUlong()
 2876    {
 2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);
 2878    }
 2879
 2880    #endregion
 2881    // NOTE this returns the offset of the first byte after the signature.
 2882    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 2883    {
 2884      using (ZipHelperStream les = new ZipHelperStream(baseStream_)) {
 2885        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
 2886      }
 2887    }
 2888
 2889    /// <summary>
 2890    /// Search for and read the central directory of a zip file filling the entries array.
 2891    /// </summary>
 2892    /// <exception cref="System.IO.IOException">
 2893    /// An i/o error occurs.
 2894    /// </exception>
 2895    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 2896    /// The central directory is malformed or cannot be found
 2897    /// </exception>
 2898    void ReadEntries()
 2899    {
 2900      // Search for the End Of Central Directory.  When a zip comment is
 2901      // present the directory will start earlier
 2902      //
 2903      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
 2904      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
 2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
 2906      // this could be invalid.
 2907      // Could also speed this up by reading memory in larger blocks.
 2908
 2909      if (baseStream_.CanSeek == false) {
 2910        throw new ZipException("ZipFile stream must be seekable");
 2911      }
 2912
 2913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2915
 2916      if (locatedEndOfCentralDir < 0) {
 2917        throw new ZipException("Cannot find central directory");
 2918      }
 2919
 2920      // Read end of central directory record
 2921      ushort thisDiskNumber = ReadLEUshort();
 2922      ushort startCentralDirDisk = ReadLEUshort();
 2923      ulong entriesForThisDisk = ReadLEUshort();
 2924      ulong entriesForWholeCentralDir = ReadLEUshort();
 2925      ulong centralDirSize = ReadLEUint();
 2926      long offsetOfCentralDir = ReadLEUint();
 2927      uint commentSize = ReadLEUshort();
 2928
 2929      if (commentSize > 0) {
 2930        byte[] comment = new byte[commentSize];
 2931
 2932        StreamUtils.ReadFully(baseStream_, comment);
 2933        comment_ = ZipConstants.ConvertToString(comment);
 2934      } else {
 2935        comment_ = string.Empty;
 2936      }
 2937
 2938      bool isZip64 = false;
 2939
 2940      // Check if zip64 header information is required.
 2941      if ((thisDiskNumber == 0xffff) ||
 2942        (startCentralDirDisk == 0xffff) ||
 2943        (entriesForThisDisk == 0xffff) ||
 2944        (entriesForWholeCentralDir == 0xffff) ||
 2945        (centralDirSize == 0xffffffff) ||
 2946        (offsetOfCentralDir == 0xffffffff)) {
 2947        isZip64 = true;
 2948
 2949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 
 2950        if (offset < 0) {
 2951          throw new ZipException("Cannot find Zip64 locator");
 2952        }
 2953
 2954        // number of the disk with the start of the zip64 end of central directory 4 bytes
 2955        // relative offset of the zip64 end of central directory record 8 bytes
 2956        // total number of disks 4 bytes
 2957        ReadLEUint(); // startDisk64 is not currently used
 2958        ulong offset64 = ReadLEUlong();
 2959        uint totalDisks = ReadLEUint();
 2960
 2961        baseStream_.Position = (long)offset64;
 2962        long sig64 = ReadLEUint();
 2963
 2964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {
 2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
 2966        }
 2967
 2968        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
 2969        ulong recordSize = ReadLEUlong();
 2970        int versionMadeBy = ReadLEUshort();
 2971        int versionToExtract = ReadLEUshort();
 2972        uint thisDisk = ReadLEUint();
 2973        uint centralDirDisk = ReadLEUint();
 2974        entriesForThisDisk = ReadLEUlong();
 2975        entriesForWholeCentralDir = ReadLEUlong();
 2976        centralDirSize = ReadLEUlong();
 2977        offsetOfCentralDir = (long)ReadLEUlong();
 2978
 2979        // NOTE: zip64 extensible data sector (variable size) is ignored.
 2980      }
 2981
 2982      entries_ = new ZipEntry[entriesForThisDisk];
 2983
 2984      // SFX/embedded support, find the offset of the first entry vis the start of the stream
 2985      // This applies to Zip files that are appended to the end of an SFX stub.
 2986      // Or are appended as a resource to an executable.
 2987      // Zip files created by some archivers have the offsets altered to reflect the true offsets
 2988      // and so dont require any adjustment here...
 2989      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
 2990      if (!isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize))) {
 2991        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
 2992        if (offsetOfFirstEntry <= 0) {
 2993          throw new ZipException("Invalid embedded zip archive");
 2994        }
 2995      }
 2996
 2997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
 2998
 2999      for (ulong i = 0; i < entriesForThisDisk; i++) {
 3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
 3001          throw new ZipException("Wrong Central Directory signature");
 3002        }
 3003
 3004        int versionMadeBy = ReadLEUshort();
 3005        int versionToExtract = ReadLEUshort();
 3006        int bitFlags = ReadLEUshort();
 3007        int method = ReadLEUshort();
 3008        uint dostime = ReadLEUint();
 3009        uint crc = ReadLEUint();
 3010        var csize = (long)ReadLEUint();
 3011        var size = (long)ReadLEUint();
 3012        int nameLen = ReadLEUshort();
 3013        int extraLen = ReadLEUshort();
 3014        int commentLen = ReadLEUshort();
 3015
 3016        int diskStartNo = ReadLEUshort();  // Not currently used
 3017        int internalAttributes = ReadLEUshort();  // Not currently used
 3018
 3019        uint externalAttributes = ReadLEUint();
 3020        long offset = ReadLEUint();
 3021
 3022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
 3023
 3024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
 3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);
 3026
 3027        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
 3028        entry.Crc = crc & 0xffffffffL;
 3029        entry.Size = size & 0xffffffffL;
 3030        entry.CompressedSize = csize & 0xffffffffL;
 3031        entry.Flags = bitFlags;
 3032        entry.DosTime = (uint)dostime;
 3033        entry.ZipFileIndex = (long)i;
 3034        entry.Offset = offset;
 3035        entry.ExternalFileAttributes = (int)externalAttributes;
 3036
 3037        if ((bitFlags & 8) == 0) {
 3038          entry.CryptoCheckValue = (byte)(crc >> 24);
 3039        } else {
 3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
 3041        }
 3042
 3043        if (extraLen > 0) {
 3044          byte[] extra = new byte[extraLen];
 3045          StreamUtils.ReadFully(baseStream_, extra);
 3046          entry.ExtraData = extra;
 3047        }
 3048
 3049        entry.ProcessExtraData(false);
 3050
 3051        if (commentLen > 0) {
 3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
 3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
 3054        }
 3055
 3056        entries_[i] = entry;
 3057      }
 3058    }
 3059
 3060    /// <summary>
 3061    /// Locate the data for a given entry.
 3062    /// </summary>
 3063    /// <returns>
 3064    /// The start offset of the data.
 3065    /// </returns>
 3066    /// <exception cref="System.IO.EndOfStreamException">
 3067    /// The stream ends prematurely
 3068    /// </exception>
 3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 3070    /// The local header signature is invalid, the entry and central header file name lengths are different
 3071    /// or the local and entry compression methods dont match
 3072    /// </exception>
 3073    long LocateEntry(ZipEntry entry)
 3074    {
 3075      return TestLocalHeader(entry, HeaderTest.Extract);
 3076    }
 3077
 3078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
 3079    {
 3080      CryptoStream result = null;
 3081
 3082      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3084        var classicManaged = new PkzipClassicManaged();
 3085
 3086        OnKeysRequired(entry.Name);
 3087        if (HaveKeys == false) {
 3088          throw new ZipException("No password available for encrypted stream");
 3089        }
 3090
 3091        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
 3092        CheckClassicPassword(result, entry);
 3093      } else {
 3094        if (entry.Version == ZipConstants.VERSION_AES) {
 3095          //
 3096          OnKeysRequired(entry.Name);
 3097          if (HaveKeys == false) {
 3098            throw new ZipException("No password available for AES encrypted stream");
 3099          }
 3100          int saltLen = entry.AESSaltLen;
 3101          byte[] saltBytes = new byte[saltLen];
 3102          int saltIn = baseStream.Read(saltBytes, 0, saltLen);
 3103          if (saltIn != saltLen)
 3104            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
 3105          //
 3106          byte[] pwdVerifyRead = new byte[2];
 3107          baseStream.Read(pwdVerifyRead, 0, 2);
 3108          int blockSize = entry.AESKeySize / 8;   // bits to bytes
 3109
 3110          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
 3111          byte[] pwdVerifyCalc = decryptor.PwdVerifier;
 3112          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
 3113            throw new ZipException("Invalid password for AES");
 3114          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
 3115        } else {
 3116          throw new ZipException("Decryption method not supported");
 3117        }
 3118      }
 3119
 3120      return result;
 3121    }
 3122
 3123    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
 3124    {
 3125      CryptoStream result = null;
 3126      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3127        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3128        var classicManaged = new PkzipClassicManaged();
 3129
 3130        OnKeysRequired(entry.Name);
 3131        if (HaveKeys == false) {
 3132          throw new ZipException("No password available for encrypted stream");
 3133        }
 3134
 3135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
 3136        // which doesnt do this.
 3137        result = new CryptoStream(new UncompressedStream(baseStream),
 3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
 3139
 3140        if ((entry.Crc < 0) || (entry.Flags & 8) != 0) {
 3141          WriteEncryptionHeader(result, entry.DosTime << 16);
 3142        } else {
 3143          WriteEncryptionHeader(result, entry.Crc);
 3144        }
 3145      }
 3146      return result;
 3147    }
 3148
 3149    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
 3150    {
 3151      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
 3152      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
 3153      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
 3154        throw new ZipException("Invalid password");
 3155      }
 3156    }
 3157
 3158    static void WriteEncryptionHeader(Stream stream, long crcValue)
 3159    {
 3160      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
 3161      var rnd = new Random();
 3162      rnd.NextBytes(cryptBuffer);
 3163      cryptBuffer[11] = (byte)(crcValue >> 24);
 3164      stream.Write(cryptBuffer, 0, cryptBuffer.Length);
 3165    }
 3166
 3167    #endregion
 3168
 3169    #region Instance Fields
 3170    bool isDisposed_;
 3171    string name_;
 3172    string comment_;
 3173    string rawPassword_;
 3174    Stream baseStream_;
 3175    bool isStreamOwner;
 3176    long offsetOfFirstEntry;
 3177    ZipEntry[] entries_;
 3178    byte[] key;
 3179    bool isNewArchive_;
 3180
 3181    // Default is dynamic which is not backwards compatible and can cause problems
 3182    // with XP's built in compression which cant read Zip64 archives.
 3183    // However it does avoid the situation were a large file is added and cannot be completed correctly.
 3184    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.
 3185    UseZip64 useZip64_ = UseZip64.Dynamic;
 3186
 3187    #region Zip Update Instance Fields
 3188    ArrayList updates_;
 3189    long updateCount_; // Count is managed manually as updates_ can contain nulls!
 3190    Hashtable updateIndex_;
 3191    IArchiveStorage archiveStorage_;
 3192    IDynamicDataSource updateDataSource_;
 3193    bool contentsEdited_;
 3194    int bufferSize_ = DefaultBufferSize;
 3195    byte[] copyBuffer_;
 3196    ZipString newComment_;
 3197    bool commentEdited_;
 3198    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();
 3199    #endregion
 3200    #endregion
 3201
 3202    #region Support Classes
 3203    /// <summary>
 3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.
 3205    /// </summary>
 3206    class ZipString
 3207    {
 3208      #region Constructors
 3209      /// <summary>
 3210      /// Initialise a <see cref="ZipString"/> with a string.
 3211      /// </summary>
 3212      /// <param name="comment">The textual string form.</param>
 3213      public ZipString(string comment)
 3214      {
 3215        comment_ = comment;
 3216        isSourceString_ = true;
 3217      }
 3218
 3219      /// <summary>
 3220      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.
 3221      /// </summary>
 3222      /// <param name="rawString"></param>
 3223      public ZipString(byte[] rawString)
 3224      {
 3225        rawComment_ = rawString;
 3226      }
 3227      #endregion
 3228
 3229      /// <summary>
 3230      /// Get a value indicating the original source of data for this instance.
 3231      /// True if the source was a string; false if the source was binary data.
 3232      /// </summary>
 3233      public bool IsSourceString {
 3234        get { return isSourceString_; }
 3235      }
 3236
 3237      /// <summary>
 3238      /// Get the length of the comment when represented as raw bytes.
 3239      /// </summary>
 3240      public int RawLength {
 3241        get {
 3242          MakeBytesAvailable();
 3243          return rawComment_.Length;
 3244        }
 3245      }
 3246
 3247      /// <summary>
 3248      /// Get the comment in its 'raw' form as plain bytes.
 3249      /// </summary>
 3250      public byte[] RawComment {
 3251        get {
 3252          MakeBytesAvailable();
 3253          return (byte[])rawComment_.Clone();
 3254        }
 3255      }
 3256
 3257      /// <summary>
 3258      /// Reset the comment to its initial state.
 3259      /// </summary>
 3260      public void Reset()
 3261      {
 3262        if (isSourceString_) {
 3263          rawComment_ = null;
 3264        } else {
 3265          comment_ = null;
 3266        }
 3267      }
 3268
 3269      void MakeTextAvailable()
 3270      {
 3271        if (comment_ == null) {
 3272          comment_ = ZipConstants.ConvertToString(rawComment_);
 3273        }
 3274      }
 3275
 3276      void MakeBytesAvailable()
 3277      {
 3278        if (rawComment_ == null) {
 3279          rawComment_ = ZipConstants.ConvertToArray(comment_);
 3280        }
 3281      }
 3282
 3283      /// <summary>
 3284      /// Implicit conversion of comment to a string.
 3285      /// </summary>
 3286      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>
 3287      /// <returns>The textual equivalent for the input value.</returns>
 3288      static public implicit operator string(ZipString zipString)
 3289      {
 3290        zipString.MakeTextAvailable();
 3291        return zipString.comment_;
 3292      }
 3293
 3294      #region Instance Fields
 3295      string comment_;
 3296      byte[] rawComment_;
 3297      bool isSourceString_;
 3298      #endregion
 3299    }
 3300
 3301    /// <summary>
 3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>
 3303    /// </summary>
 3304    class ZipEntryEnumerator : IEnumerator
 3305    {
 3306      #region Constructors
 3307      public ZipEntryEnumerator(ZipEntry[] entries)
 3308      {
 3309        array = entries;
 3310      }
 3311
 3312      #endregion
 3313      #region IEnumerator Members
 3314      public object Current {
 3315        get {
 3316          return array[index];
 3317        }
 3318      }
 3319
 3320      public void Reset()
 3321      {
 3322        index = -1;
 3323      }
 3324
 3325      public bool MoveNext()
 3326      {
 3327        return (++index < array.Length);
 3328      }
 3329      #endregion
 3330      #region Instance Fields
 3331      ZipEntry[] array;
 3332      int index = -1;
 3333      #endregion
 3334    }
 3335
 3336    /// <summary>
 3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data
 3338    /// to and flush, but cannot read, seek or do anything else to.
 3339    /// </summary>
 3340    class UncompressedStream : Stream
 3341    {
 3342      #region Constructors
 3343      public UncompressedStream(Stream baseStream)
 3344      {
 3345        baseStream_ = baseStream;
 3346      }
 3347
 3348      #endregion
 3349
 3350      /// <summary>
 3351      /// Close this stream instance.
 3352      /// </summary>
 3353      public override void Close()
 3354      {
 3355        // Do nothing
 3356      }
 3357
 3358      /// <summary>
 3359      /// Gets a value indicating whether the current stream supports reading.
 3360      /// </summary>
 3361      public override bool CanRead {
 3362        get {
 3363          return false;
 3364        }
 3365      }
 3366
 3367      /// <summary>
 3368      /// Write any buffered data to underlying storage.
 3369      /// </summary>
 3370      public override void Flush()
 3371      {
 3372        baseStream_.Flush();
 3373      }
 3374
 3375      /// <summary>
 3376      /// Gets a value indicating whether the current stream supports writing.
 3377      /// </summary>
 3378      public override bool CanWrite {
 3379        get {
 3380          return baseStream_.CanWrite;
 3381        }
 3382      }
 3383
 3384      /// <summary>
 3385      /// Gets a value indicating whether the current stream supports seeking.
 3386      /// </summary>
 3387      public override bool CanSeek {
 3388        get {
 3389          return false;
 3390        }
 3391      }
 3392
 3393      /// <summary>
 3394      /// Get the length in bytes of the stream.
 3395      /// </summary>
 3396      public override long Length {
 3397        get {
 3398          return 0;
 3399        }
 3400      }
 3401
 3402      /// <summary>
 3403      /// Gets or sets the position within the current stream.
 3404      /// </summary>
 3405      public override long Position {
 3406        get {
 3407          return baseStream_.Position;
 3408        }
 3409        set {
 3410          throw new NotImplementedException();
 3411        }
 3412      }
 3413
 3414      /// <summary>
 3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3416      /// </summary>
 3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3419      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3420      /// <returns>
 3421      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3422      /// </returns>
 3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3425      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3426      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3427      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3428      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3429      public override int Read(byte[] buffer, int offset, int count)
 3430      {
 3431        return 0;
 3432      }
 3433
 3434      /// <summary>
 3435      /// Sets the position within the current stream.
 3436      /// </summary>
 3437      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3438      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3439      /// <returns>
 3440      /// The new position within the current stream.
 3441      /// </returns>
 3442      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3443      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3445      public override long Seek(long offset, SeekOrigin origin)
 3446      {
 3447        return 0;
 3448      }
 3449
 3450      /// <summary>
 3451      /// Sets the length of the current stream.
 3452      /// </summary>
 3453      /// <param name="value">The desired length of the current stream in bytes.</param>
 3454      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3455      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3456      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3457      public override void SetLength(long value)
 3458      {
 3459      }
 3460
 3461      /// <summary>
 3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3463      /// </summary>
 3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3466      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3467      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3468      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3469      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3470      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3471      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3472      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3473      public override void Write(byte[] buffer, int offset, int count)
 3474      {
 3475        baseStream_.Write(buffer, offset, count);
 3476      }
 3477
 3478      readonly
 3479
 3480      #region Instance Fields
 3481      Stream baseStream_;
 3482      #endregion
 3483    }
 3484
 3485    /// <summary>
 3486    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>
 3487    /// whose data is only a part or subsection of a file.
 3488    /// </summary>
 3489    class PartialInputStream : Stream
 3490    {
 3491      #region Constructors
 3492      /// <summary>
 3493      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.
 3494      /// </summary>
 3495      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>
 3496      /// <param name="start">The start of the partial data.</param>
 3497      /// <param name="length">The length of the partial data.</param>
 3498      public PartialInputStream(ZipFile zipFile, long start, long length)
 3499      {
 3500        start_ = start;
 3501        length_ = length;
 3502
 3503        // Although this is the only time the zipfile is used
 3504        // keeping a reference here prevents premature closure of
 3505        // this zip file and thus the baseStream_.
 3506
 3507        // Code like this will cause apparently random failures depending
 3508        // on the size of the files and when garbage is collected.
 3509        //
 3510        // ZipFile z = new ZipFile (stream);
 3511        // Stream reader = z.GetInputStream(0);
 3512        // uses reader here....
 3513        zipFile_ = zipFile;
 3514        baseStream_ = zipFile_.baseStream_;
 3515        readPos_ = start;
 3516        end_ = start + length;
 3517      }
 3518      #endregion
 3519
 3520      /// <summary>
 3521      /// Read a byte from this stream.
 3522      /// </summary>
 3523      /// <returns>Returns the byte read or -1 on end of stream.</returns>
 3524      public override int ReadByte()
 3525      {
 3526        if (readPos_ >= end_) {
 3527          // -1 is the correct value at end of stream.
 3528          return -1;
 3529        }
 3530
 3531        lock (baseStream_) {
 3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);
 3533          return baseStream_.ReadByte();
 3534        }
 3535      }
 3536
 3537      /// <summary>
 3538      /// Close this <see cref="PartialInputStream">partial input stream</see>.
 3539      /// </summary>
 3540      /// <remarks>
 3541      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.
 3542      /// </remarks>
 3543      public override void Close()
 3544      {
 3545        // Do nothing at all!
 3546      }
 3547
 3548      /// <summary>
 3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3550      /// </summary>
 3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3553      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3554      /// <returns>
 3555      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3556      /// </returns>
 3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3559      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3560      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3561      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3562      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3563      public override int Read(byte[] buffer, int offset, int count)
 3564      {
 3565        lock (baseStream_) {
 3566          if (count > end_ - readPos_) {
 3567            count = (int)(end_ - readPos_);
 3568            if (count == 0) {
 3569              return 0;
 3570            }
 3571          }
 3572          // Protect against Stream implementations that throw away their buffer on every Seek
 3573          // (for example, Mono FileStream)
 3574          if (baseStream_.Position != readPos_) {
 3575            baseStream_.Seek(readPos_, SeekOrigin.Begin);
 3576          }
 3577          int readCount = baseStream_.Read(buffer, offset, count);
 3578          if (readCount > 0) {
 3579            readPos_ += readCount;
 3580          }
 3581          return readCount;
 3582        }
 3583      }
 3584
 3585      /// <summary>
 3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3587      /// </summary>
 3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3590      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3591      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3592      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3593      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3594      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3595      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3596      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3597      public override void Write(byte[] buffer, int offset, int count)
 3598      {
 3599        throw new NotSupportedException();
 3600      }
 3601
 3602      /// <summary>
 3603      /// When overridden in a derived class, sets the length of the current stream.
 3604      /// </summary>
 3605      /// <param name="value">The desired length of the current stream in bytes.</param>
 3606      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3607      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3608      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3609      public override void SetLength(long value)
 3610      {
 3611        throw new NotSupportedException();
 3612      }
 3613
 3614      /// <summary>
 3615      /// When overridden in a derived class, sets the position within the current stream.
 3616      /// </summary>
 3617      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3618      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3619      /// <returns>
 3620      /// The new position within the current stream.
 3621      /// </returns>
 3622      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3623      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3625      public override long Seek(long offset, SeekOrigin origin)
 3626      {
 3627        long newPos = readPos_;
 3628
 3629        switch (origin) {
 3630          case SeekOrigin.Begin:
 3631            newPos = start_ + offset;
 3632            break;
 3633
 3634          case SeekOrigin.Current:
 3635            newPos = readPos_ + offset;
 3636            break;
 3637
 3638          case SeekOrigin.End:
 3639            newPos = end_ + offset;
 3640            break;
 3641        }
 3642
 3643        if (newPos < start_) {
 3644          throw new ArgumentException("Negative position is invalid");
 3645        }
 3646
 3647        if (newPos >= end_) {
 3648          throw new IOException("Cannot seek past end");
 3649        }
 3650        readPos_ = newPos;
 3651        return readPos_;
 3652      }
 3653
 3654      /// <summary>
 3655      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
 3656      /// </summary>
 3657      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3658      public override void Flush()
 3659      {
 3660        // Nothing to do.
 3661      }
 3662
 3663      /// <summary>
 3664      /// Gets or sets the position within the current stream.
 3665      /// </summary>
 3666      /// <value></value>
 3667      /// <returns>The current position within the stream.</returns>
 3668      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3669      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>
 3670      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3671      public override long Position {
 3672        get { return readPos_ - start_; }
 3673        set {
 3674          long newPos = start_ + value;
 3675
 3676          if (newPos < start_) {
 3677            throw new ArgumentException("Negative position is invalid");
 3678          }
 3679
 3680          if (newPos >= end_) {
 3681            throw new InvalidOperationException("Cannot seek past end");
 3682          }
 3683          readPos_ = newPos;
 3684        }
 3685      }
 3686
 3687      /// <summary>
 3688      /// Gets the length in bytes of the stream.
 3689      /// </summary>
 3690      /// <value></value>
 3691      /// <returns>A long value representing the length of the stream in bytes.</returns>
 3692      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep
 3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3694      public override long Length {
 3695        get { return length_; }
 3696      }
 3697
 3698      /// <summary>
 3699      /// Gets a value indicating whether the current stream supports writing.
 3700      /// </summary>
 3701      /// <value>false</value>
 3702      /// <returns>true if the stream supports writing; otherwise, false.</returns>
 3703      public override bool CanWrite {
 3704        get { return false; }
 3705      }
 3706
 3707      /// <summary>
 3708      /// Gets a value indicating whether the current stream supports seeking.
 3709      /// </summary>
 3710      /// <value>true</value>
 3711      /// <returns>true if the stream supports seeking; otherwise, false.</returns>
 3712      public override bool CanSeek {
 3713        get { return true; }
 3714      }
 3715
 3716      /// <summary>
 3717      /// Gets a value indicating whether the current stream supports reading.
 3718      /// </summary>
 3719      /// <value>true.</value>
 3720      /// <returns>true if the stream supports reading; otherwise, false.</returns>
 3721      public override bool CanRead {
 3722        get { return true; }
 3723      }
 3724
 3725      /// <summary>
 3726      /// Gets a value that determines whether the current stream can time out.
 3727      /// </summary>
 3728      /// <value></value>
 3729      /// <returns>A value that determines whether the current stream can time out.</returns>
 3730      public override bool CanTimeout {
 3731        get { return baseStream_.CanTimeout; }
 3732      }
 3733      #region Instance Fields
 3734      ZipFile zipFile_;
 3735      Stream baseStream_;
 3736      long start_;
 3737      long length_;
 3738      long readPos_;
 3739      long end_;
 3740      #endregion
 3741    }
 3742    #endregion
 3743  }
 3744
 3745  #endregion
 3746
 3747  #region DataSources
 3748  /// <summary>
 3749  /// Provides a static way to obtain a source of data for an entry.
 3750  /// </summary>
 3751  public interface IStaticDataSource
 3752  {
 3753    /// <summary>
 3754    /// Get a source of data by creating a new stream.
 3755    /// </summary>
 3756    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3757    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3758    Stream GetSource();
 3759  }
 3760
 3761  /// <summary>
 3762  /// Represents a source of data that can dynamically provide
 3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.
 3764  /// </summary>
 3765  public interface IDynamicDataSource
 3766  {
 3767    /// <summary>
 3768    /// Get a data source.
 3769    /// </summary>
 3770    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>
 3771    /// <param name="name">The name for data if known.</param>
 3772    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3773    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3774    Stream GetSource(ZipEntry entry, string name);
 3775  }
 3776
 3777  /// <summary>
 3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.
 3779  /// </summary>
 3780  public class StaticDiskDataSource : IStaticDataSource
 3781  {
 3782    /// <summary>
 3783    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>
 3784    /// </summary>
 3785    /// <param name="fileName">The name of the file to obtain data from.</param>
 3786    public StaticDiskDataSource(string fileName)
 3787    {
 3788      fileName_ = fileName;
 3789    }
 3790
 3791    #region IDataSource Members
 3792
 3793    /// <summary>
 3794    /// Get a <see cref="Stream"/> providing data.
 3795    /// </summary>
 3796    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>
 3797    public Stream GetSource()
 3798    {
 3799      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 3800    }
 3801
 3802    readonly
 3803
 3804    #endregion
 3805    #region Instance Fields
 3806    string fileName_;
 3807    #endregion
 3808  }
 3809
 3810
 3811  /// <summary>
 3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.
 3813  /// </summary>
 3814  public class DynamicDiskDataSource : IDynamicDataSource
 3815  {
 3816
 3817    #region IDataSource Members
 3818    /// <summary>
 3819    /// Get a <see cref="Stream"/> providing data for an entry.
 3820    /// </summary>
 3821    /// <param name="entry">The entry to provide data for.</param>
 3822    /// <param name="name">The file name for data if known.</param>
 3823    /// <returns>Returns a stream providing data; or null if not available</returns>
 3824    public Stream GetSource(ZipEntry entry, string name)
 3825    {
 655403826      Stream result = null;
 3827
 655403828       if (name != null) {
 33829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 3830      }
 3831
 655403832      return result;
 3833    }
 3834
 3835    #endregion
 3836  }
 3837
 3838  #endregion
 3839
 3840  #region Archive Storage
 3841  /// <summary>
 3842  /// Defines facilities for data storage when updating Zip Archives.
 3843  /// </summary>
 3844  public interface IArchiveStorage
 3845  {
 3846    /// <summary>
 3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.
 3848    /// </summary>
 3849    FileUpdateMode UpdateMode { get; }
 3850
 3851    /// <summary>
 3852    /// Get an empty <see cref="Stream"/> that can be used for temporary output.
 3853    /// </summary>
 3854    /// <returns>Returns a temporary output <see cref="Stream"/></returns>
 3855    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3856    Stream GetTemporaryOutput();
 3857
 3858    /// <summary>
 3859    /// Convert a temporary output stream to a final stream.
 3860    /// </summary>
 3861    /// <returns>The resulting final <see cref="Stream"/></returns>
 3862    /// <seealso cref="GetTemporaryOutput"/>
 3863    Stream ConvertTemporaryToFinal();
 3864
 3865    /// <summary>
 3866    /// Make a temporary copy of the original stream.
 3867    /// </summary>
 3868    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 3869    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3870    Stream MakeTemporaryCopy(Stream stream);
 3871
 3872    /// <summary>
 3873    /// Return a stream suitable for performing direct updates on the original source.
 3874    /// </summary>
 3875    /// <param name="stream">The current stream.</param>
 3876    /// <returns>Returns a stream suitable for direct updating.</returns>
 3877    /// <remarks>This may be the current stream passed.</remarks>
 3878    Stream OpenForDirectUpdate(Stream stream);
 3879
 3880    /// <summary>
 3881    /// Dispose of this instance.
 3882    /// </summary>
 3883    void Dispose();
 3884  }
 3885
 3886  /// <summary>
 3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.
 3888  /// </summary>
 3889  abstract public class BaseArchiveStorage : IArchiveStorage
 3890  {
 3891    #region Constructors
 3892    /// <summary>
 3893    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.
 3894    /// </summary>
 3895    /// <param name="updateMode">The update mode.</param>
 3896    protected BaseArchiveStorage(FileUpdateMode updateMode)
 3897    {
 3898      updateMode_ = updateMode;
 3899    }
 3900    #endregion
 3901
 3902    #region IArchiveStorage Members
 3903
 3904    /// <summary>
 3905    /// Gets a temporary output <see cref="Stream"/>
 3906    /// </summary>
 3907    /// <returns>Returns the temporary output stream.</returns>
 3908    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3909    public abstract Stream GetTemporaryOutput();
 3910
 3911    /// <summary>
 3912    /// Converts the temporary <see cref="Stream"/> to its final form.
 3913    /// </summary>
 3914    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 3915    /// the final storage for the archive.</returns>
 3916    /// <seealso cref="GetTemporaryOutput"/>
 3917    public abstract Stream ConvertTemporaryToFinal();
 3918
 3919    /// <summary>
 3920    /// Make a temporary copy of a <see cref="Stream"/>.
 3921    /// </summary>
 3922    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>
 3923    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3924    public abstract Stream MakeTemporaryCopy(Stream stream);
 3925
 3926    /// <summary>
 3927    /// Return a stream suitable for performing direct updates on the original source.
 3928    /// </summary>
 3929    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>
 3930    /// <returns>Returns a stream suitable for direct updating.</returns>
 3931    public abstract Stream OpenForDirectUpdate(Stream stream);
 3932
 3933    /// <summary>
 3934    /// Disposes this instance.
 3935    /// </summary>
 3936    public abstract void Dispose();
 3937
 3938    /// <summary>
 3939    /// Gets the update mode applicable.
 3940    /// </summary>
 3941    /// <value>The update mode.</value>
 3942    public FileUpdateMode UpdateMode {
 3943      get {
 3944        return updateMode_;
 3945      }
 3946    }
 3947
 3948    #endregion
 3949
 3950    #region Instance Fields
 3951    FileUpdateMode updateMode_;
 3952    #endregion
 3953  }
 3954
 3955  /// <summary>
 3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.
 3957  /// </summary>
 3958  public class DiskArchiveStorage : BaseArchiveStorage
 3959  {
 3960    #region Constructors
 3961    /// <summary>
 3962    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3963    /// </summary>
 3964    /// <param name="file">The file.</param>
 3965    /// <param name="updateMode">The update mode.</param>
 3966    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)
 3967      : base(updateMode)
 3968    {
 3969      if (file.Name == null) {
 3970        throw new ZipException("Cant handle non file archives");
 3971      }
 3972
 3973      fileName_ = file.Name;
 3974    }
 3975
 3976    /// <summary>
 3977    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3978    /// </summary>
 3979    /// <param name="file">The file.</param>
 3980    public DiskArchiveStorage(ZipFile file)
 3981      : this(file, FileUpdateMode.Safe)
 3982    {
 3983    }
 3984    #endregion
 3985
 3986    #region IArchiveStorage Members
 3987
 3988    /// <summary>
 3989    /// Gets a temporary output <see cref="Stream"/> for performing updates on.
 3990    /// </summary>
 3991    /// <returns>Returns the temporary output stream.</returns>
 3992    public override Stream GetTemporaryOutput()
 3993    {
 3994      if (temporaryName_ != null) {
 3995        temporaryName_ = GetTempFileName(temporaryName_, true);
 3996        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 3997      } else {
 3998        // Determine where to place files based on internal strategy.
 3999        // Currently this is always done in system temp directory.
 4000        temporaryName_ = Path.GetTempFileName();
 4001        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 4002      }
 4003
 4004      return temporaryStream_;
 4005    }
 4006
 4007    /// <summary>
 4008    /// Converts a temporary <see cref="Stream"/> to its final form.
 4009    /// </summary>
 4010    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4011    /// the final storage for the archive.</returns>
 4012    public override Stream ConvertTemporaryToFinal()
 4013    {
 4014      if (temporaryStream_ == null) {
 4015        throw new ZipException("No temporary stream has been created");
 4016      }
 4017
 4018      Stream result = null;
 4019
 4020      string moveTempName = GetTempFileName(fileName_, false);
 4021      bool newFileCreated = false;
 4022
 4023      try {
 4024        temporaryStream_.Close();
 4025        File.Move(fileName_, moveTempName);
 4026        File.Move(temporaryName_, fileName_);
 4027        newFileCreated = true;
 4028        File.Delete(moveTempName);
 4029
 4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 4031      } catch (Exception) {
 4032        result = null;
 4033
 4034        // Try to roll back changes...
 4035        if (!newFileCreated) {
 4036          File.Move(moveTempName, fileName_);
 4037          File.Delete(temporaryName_);
 4038        }
 4039
 4040        throw;
 4041      }
 4042
 4043      return result;
 4044    }
 4045
 4046    /// <summary>
 4047    /// Make a temporary copy of a stream.
 4048    /// </summary>
 4049    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4050    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4051    public override Stream MakeTemporaryCopy(Stream stream)
 4052    {
 4053      stream.Close();
 4054
 4055      temporaryName_ = GetTempFileName(fileName_, true);
 4056      File.Copy(fileName_, temporaryName_, true);
 4057
 4058      temporaryStream_ = new FileStream(temporaryName_,
 4059        FileMode.Open,
 4060        FileAccess.ReadWrite);
 4061      return temporaryStream_;
 4062    }
 4063
 4064    /// <summary>
 4065    /// Return a stream suitable for performing direct updates on the original source.
 4066    /// </summary>
 4067    /// <param name="stream">The current stream.</param>
 4068    /// <returns>Returns a stream suitable for direct updating.</returns>
 4069    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>
 4070    public override Stream OpenForDirectUpdate(Stream stream)
 4071    {
 4072      Stream result;
 4073      if ((stream == null) || !stream.CanWrite) {
 4074        if (stream != null) {
 4075          stream.Close();
 4076        }
 4077
 4078        result = new FileStream(fileName_,
 4079            FileMode.Open,
 4080            FileAccess.ReadWrite);
 4081      } else {
 4082        result = stream;
 4083      }
 4084
 4085      return result;
 4086    }
 4087
 4088    /// <summary>
 4089    /// Disposes this instance.
 4090    /// </summary>
 4091    public override void Dispose()
 4092    {
 4093      if (temporaryStream_ != null) {
 4094        temporaryStream_.Close();
 4095      }
 4096    }
 4097
 4098    #endregion
 4099
 4100    #region Internal routines
 4101    static string GetTempFileName(string original, bool makeTempFile)
 4102    {
 4103      string result = null;
 4104
 4105      if (original == null) {
 4106        result = Path.GetTempFileName();
 4107      } else {
 4108        int counter = 0;
 4109        int suffixSeed = DateTime.Now.Second;
 4110
 4111        while (result == null) {
 4112          counter += 1;
 4113          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);
 4114          if (!File.Exists(newName)) {
 4115            if (makeTempFile) {
 4116              try {
 4117                // Try and create the file.
 4118                using (FileStream stream = File.Create(newName)) {
 4119                }
 4120                result = newName;
 4121              } catch {
 4122                suffixSeed = DateTime.Now.Second;
 4123              }
 4124            } else {
 4125              result = newName;
 4126            }
 4127          }
 4128        }
 4129      }
 4130      return result;
 4131    }
 4132    #endregion
 4133
 4134    #region Instance Fields
 4135    Stream temporaryStream_;
 4136    string fileName_;
 4137    string temporaryName_;
 4138    #endregion
 4139  }
 4140
 4141  /// <summary>
 4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.
 4143  /// </summary>
 4144  public class MemoryArchiveStorage : BaseArchiveStorage
 4145  {
 4146    #region Constructors
 4147    /// <summary>
 4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4149    /// </summary>
 4150    public MemoryArchiveStorage()
 4151      : base(FileUpdateMode.Direct)
 4152    {
 4153    }
 4154
 4155    /// <summary>
 4156    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4157    /// </summary>
 4158    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>
 4159    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>
 4160    public MemoryArchiveStorage(FileUpdateMode updateMode)
 4161      : base(updateMode)
 4162    {
 4163    }
 4164
 4165    #endregion
 4166
 4167    #region Properties
 4168    /// <summary>
 4169    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.
 4170    /// </summary>
 4171    public MemoryStream FinalStream {
 4172      get { return finalStream_; }
 4173    }
 4174
 4175    #endregion
 4176
 4177    #region IArchiveStorage Members
 4178
 4179    /// <summary>
 4180    /// Gets the temporary output <see cref="Stream"/>
 4181    /// </summary>
 4182    /// <returns>Returns the temporary output stream.</returns>
 4183    public override Stream GetTemporaryOutput()
 4184    {
 4185      temporaryStream_ = new MemoryStream();
 4186      return temporaryStream_;
 4187    }
 4188
 4189    /// <summary>
 4190    /// Converts the temporary <see cref="Stream"/> to its final form.
 4191    /// </summary>
 4192    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4193    /// the final storage for the archive.</returns>
 4194    public override Stream ConvertTemporaryToFinal()
 4195    {
 4196      if (temporaryStream_ == null) {
 4197        throw new ZipException("No temporary stream has been created");
 4198      }
 4199
 4200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());
 4201      return finalStream_;
 4202    }
 4203
 4204    /// <summary>
 4205    /// Make a temporary copy of the original stream.
 4206    /// </summary>
 4207    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4208    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4209    public override Stream MakeTemporaryCopy(Stream stream)
 4210    {
 4211      temporaryStream_ = new MemoryStream();
 4212      stream.Position = 0;
 4213      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);
 4214      return temporaryStream_;
 4215    }
 4216
 4217    /// <summary>
 4218    /// Return a stream suitable for performing direct updates on the original source.
 4219    /// </summary>
 4220    /// <param name="stream">The original source stream</param>
 4221    /// <returns>Returns a stream suitable for direct updating.</returns>
 4222    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;
 4223    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>
 4224    public override Stream OpenForDirectUpdate(Stream stream)
 4225    {
 4226      Stream result;
 4227      if ((stream == null) || !stream.CanWrite) {
 4228
 4229        result = new MemoryStream();
 4230
 4231        if (stream != null) {
 4232          stream.Position = 0;
 4233          StreamUtils.Copy(stream, result, new byte[4096]);
 4234
 4235          stream.Close();
 4236        }
 4237      } else {
 4238        result = stream;
 4239      }
 4240
 4241      return result;
 4242    }
 4243
 4244    /// <summary>
 4245    /// Disposes this instance.
 4246    /// </summary>
 4247    public override void Dispose()
 4248    {
 4249      if (temporaryStream_ != null) {
 4250        temporaryStream_.Close();
 4251      }
 4252    }
 4253
 4254    #endregion
 4255
 4256    #region Instance Fields
 4257    MemoryStream temporaryStream_;
 4258    MemoryStream finalStream_;
 4259    #endregion
 4260  }
 4261
 4262  #endregion
 4263}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_EntryPatchData.htm b/docs/opencover/ICSharpCode.SharpZipLib_EntryPatchData.htm new file mode 100644 index 000000000..7df2ab838 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_EntryPatchData.htm @@ -0,0 +1,594 @@ + + + + +ICSharpCode.SharpZipLib.Zip.EntryPatchData - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.EntryPatchData
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipHelperStream.cs
Covered lines:0
Uncovered lines:4
Coverable lines:4
Total lines:560
Line coverage:0%
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipHelperStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Text;
 4
 5namespace ICSharpCode.SharpZipLib.Zip
 6{
 7  /// <summary>
 8  /// Holds data pertinent to a data descriptor.
 9  /// </summary>
 10  public class DescriptorData
 11  {
 12    /// <summary>
 13    /// Get /set the compressed size of data.
 14    /// </summary>
 15    public long CompressedSize {
 16      get { return compressedSize; }
 17      set { compressedSize = value; }
 18    }
 19
 20    /// <summary>
 21    /// Get / set the uncompressed size of data
 22    /// </summary>
 23    public long Size {
 24      get { return size; }
 25      set { size = value; }
 26    }
 27
 28    /// <summary>
 29    /// Get /set the crc value.
 30    /// </summary>
 31    public long Crc {
 32      get { return crc; }
 33      set { crc = (value & 0xffffffff); }
 34    }
 35
 36    #region Instance Fields
 37    long size;
 38    long compressedSize;
 39    long crc;
 40    #endregion
 41  }
 42
 43  class EntryPatchData
 44  {
 45    public long SizePatchOffset {
 046      get { return sizePatchOffset_; }
 047      set { sizePatchOffset_ = value; }
 48    }
 49
 50    public long CrcPatchOffset {
 051      get { return crcPatchOffset_; }
 052      set { crcPatchOffset_ = value; }
 53    }
 54
 55    #region Instance Fields
 56    long sizePatchOffset_;
 57    long crcPatchOffset_;
 58    #endregion
 59  }
 60
 61  /// <summary>
 62  /// This class assists with writing/reading from Zip files.
 63  /// </summary>
 64  internal class ZipHelperStream : Stream
 65  {
 66    #region Constructors
 67    /// <summary>
 68    /// Initialise an instance of this class.
 69    /// </summary>
 70    /// <param name="name">The name of the file to open.</param>
 71    public ZipHelperStream(string name)
 72    {
 73      stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite);
 74      isOwner_ = true;
 75    }
 76
 77    /// <summary>
 78    /// Initialise a new instance of <see cref="ZipHelperStream"/>.
 79    /// </summary>
 80    /// <param name="stream">The stream to use.</param>
 81    public ZipHelperStream(Stream stream)
 82    {
 83      stream_ = stream;
 84    }
 85    #endregion
 86
 87    /// <summary>
 88    /// Get / set a value indicating wether the the underlying stream is owned or not.
 89    /// </summary>
 90    /// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>
 91    public bool IsStreamOwner {
 92      get { return isOwner_; }
 93      set { isOwner_ = value; }
 94    }
 95
 96    #region Base Stream Methods
 97    public override bool CanRead {
 98      get { return stream_.CanRead; }
 99    }
 100
 101    public override bool CanSeek {
 102      get { return stream_.CanSeek; }
 103    }
 104
 105    public override bool CanTimeout {
 106      get { return stream_.CanTimeout; }
 107    }
 108
 109    public override long Length {
 110      get { return stream_.Length; }
 111    }
 112
 113    public override long Position {
 114      get { return stream_.Position; }
 115      set { stream_.Position = value; }
 116    }
 117
 118    public override bool CanWrite {
 119      get { return stream_.CanWrite; }
 120    }
 121
 122    public override void Flush()
 123    {
 124      stream_.Flush();
 125    }
 126
 127    public override long Seek(long offset, SeekOrigin origin)
 128    {
 129      return stream_.Seek(offset, origin);
 130    }
 131
 132    public override void SetLength(long value)
 133    {
 134      stream_.SetLength(value);
 135    }
 136
 137    public override int Read(byte[] buffer, int offset, int count)
 138    {
 139      return stream_.Read(buffer, offset, count);
 140    }
 141
 142    public override void Write(byte[] buffer, int offset, int count)
 143    {
 144      stream_.Write(buffer, offset, count);
 145    }
 146
 147    /// <summary>
 148    /// Close the stream.
 149    /// </summary>
 150    /// <remarks>
 151    /// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.
 152    /// </remarks>
 153    override public void Close()
 154    {
 155      Stream toClose = stream_;
 156      stream_ = null;
 157      if (isOwner_ && (toClose != null)) {
 158        isOwner_ = false;
 159        toClose.Close();
 160      }
 161    }
 162    #endregion
 163
 164    // Write the local file header
 165    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
 166    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
 167    {
 168      CompressionMethod method = entry.CompressionMethod;
 169      bool headerInfoAvailable = true; // How to get this?
 170      bool patchEntryHeader = false;
 171
 172      WriteLEInt(ZipConstants.LocalHeaderSignature);
 173
 174      WriteLEShort(entry.Version);
 175      WriteLEShort(entry.Flags);
 176      WriteLEShort((byte)method);
 177      WriteLEInt((int)entry.DosTime);
 178
 179      if (headerInfoAvailable == true) {
 180        WriteLEInt((int)entry.Crc);
 181        if (entry.LocalHeaderRequiresZip64) {
 182          WriteLEInt(-1);
 183          WriteLEInt(-1);
 184        } else {
 185          WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.Compressed
 186          WriteLEInt((int)entry.Size);
 187        }
 188      } else {
 189        if (patchData != null) {
 190          patchData.CrcPatchOffset = stream_.Position;
 191        }
 192        WriteLEInt(0);  // Crc
 193
 194        if (patchData != null) {
 195          patchData.SizePatchOffset = stream_.Position;
 196        }
 197
 198        // For local header both sizes appear in Zip64 Extended Information
 199        if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {
 200          WriteLEInt(-1);
 201          WriteLEInt(-1);
 202        } else {
 203          WriteLEInt(0);  // Compressed size
 204          WriteLEInt(0);  // Uncompressed size
 205        }
 206      }
 207
 208      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 209
 210      if (name.Length > 0xFFFF) {
 211        throw new ZipException("Entry name too long.");
 212      }
 213
 214      var ed = new ZipExtraData(entry.ExtraData);
 215
 216      if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) {
 217        ed.StartNewEntry();
 218        if (headerInfoAvailable) {
 219          ed.AddLeLong(entry.Size);
 220          ed.AddLeLong(entry.CompressedSize);
 221        } else {
 222          ed.AddLeLong(-1);
 223          ed.AddLeLong(-1);
 224        }
 225        ed.AddNewEntry(1);
 226
 227        if (!ed.Find(1)) {
 228          throw new ZipException("Internal error cant find extra data");
 229        }
 230
 231        if (patchData != null) {
 232          patchData.SizePatchOffset = ed.CurrentReadIndex;
 233        }
 234      } else {
 235        ed.Delete(1);
 236      }
 237
 238      byte[] extra = ed.GetEntryData();
 239
 240      WriteLEShort(name.Length);
 241      WriteLEShort(extra.Length);
 242
 243      if (name.Length > 0) {
 244        stream_.Write(name, 0, name.Length);
 245      }
 246
 247      if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {
 248        patchData.SizePatchOffset += stream_.Position;
 249      }
 250
 251      if (extra.Length > 0) {
 252        stream_.Write(extra, 0, extra.Length);
 253      }
 254    }
 255
 256    /// <summary>
 257    /// Locates a block with the desired <paramref name="signature"/>.
 258    /// </summary>
 259    /// <param name="signature">The signature to find.</param>
 260    /// <param name="endLocation">Location, marking the end of block.</param>
 261    /// <param name="minimumBlockSize">Minimum size of the block.</param>
 262    /// <param name="maximumVariableData">The maximum variable data.</param>
 263    /// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns>
 264    public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 265    {
 266      long pos = endLocation - minimumBlockSize;
 267      if (pos < 0) {
 268        return -1;
 269      }
 270
 271      long giveUpMarker = Math.Max(pos - maximumVariableData, 0);
 272
 273      // TODO: This loop could be optimised for speed.
 274      do {
 275        if (pos < giveUpMarker) {
 276          return -1;
 277        }
 278        Seek(pos--, SeekOrigin.Begin);
 279      } while (ReadLEInt() != signature);
 280
 281      return Position;
 282    }
 283
 284    /// <summary>
 285    /// Write Zip64 end of central directory records (File header and locator).
 286    /// </summary>
 287    /// <param name="noOfEntries">The number of entries in the central directory.</param>
 288    /// <param name="sizeEntries">The size of entries in the central directory.</param>
 289    /// <param name="centralDirOffset">The offset of the dentral directory.</param>
 290    public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)
 291    {
 292      long centralSignatureOffset = stream_.Position;
 293      WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature);
 294      WriteLELong(44);    // Size of this record (total size of remaining fields in header or full size - 12)
 295      WriteLEShort(ZipConstants.VersionMadeBy);   // Version made by
 296      WriteLEShort(ZipConstants.VersionZip64);   // Version to extract
 297      WriteLEInt(0);      // Number of this disk
 298      WriteLEInt(0);      // number of the disk with the start of the central directory
 299      WriteLELong(noOfEntries);       // No of entries on this disk
 300      WriteLELong(noOfEntries);       // Total No of entries in central directory
 301      WriteLELong(sizeEntries);       // Size of the central directory
 302      WriteLELong(centralDirOffset);  // offset of start of central directory
 303                      // zip64 extensible data sector not catered for here (variable size)
 304
 305      // Write the Zip64 end of central directory locator
 306      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);
 307
 308      // no of the disk with the start of the zip64 end of central directory
 309      WriteLEInt(0);
 310
 311      // relative offset of the zip64 end of central directory record
 312      WriteLELong(centralSignatureOffset);
 313
 314      // total number of disks
 315      WriteLEInt(1);
 316    }
 317
 318    /// <summary>
 319    /// Write the required records to end the central directory.
 320    /// </summary>
 321    /// <param name="noOfEntries">The number of entries in the directory.</param>
 322    /// <param name="sizeEntries">The size of the entries in the directory.</param>
 323    /// <param name="startOfCentralDirectory">The start of the central directory.</param>
 324    /// <param name="comment">The archive comment.  (This can be null).</param>
 325    public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,
 326      long startOfCentralDirectory, byte[] comment)
 327    {
 328
 329      if ((noOfEntries >= 0xffff) ||
 330        (startOfCentralDirectory >= 0xffffffff) ||
 331        (sizeEntries >= 0xffffffff)) {
 332        WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);
 333      }
 334
 335      WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);
 336
 337      // TODO: ZipFile Multi disk handling not done
 338      WriteLEShort(0);                    // number of this disk
 339      WriteLEShort(0);                    // no of disk with start of central dir
 340
 341
 342      // Number of entries
 343      if (noOfEntries >= 0xffff) {
 344        WriteLEUshort(0xffff);  // Zip64 marker
 345        WriteLEUshort(0xffff);
 346      } else {
 347        WriteLEShort((short)noOfEntries);          // entries in central dir for this disk
 348        WriteLEShort((short)noOfEntries);          // total entries in central directory
 349      }
 350
 351      // Size of the central directory
 352      if (sizeEntries >= 0xffffffff) {
 353        WriteLEUint(0xffffffff);    // Zip64 marker
 354      } else {
 355        WriteLEInt((int)sizeEntries);
 356      }
 357
 358
 359      // offset of start of central directory
 360      if (startOfCentralDirectory >= 0xffffffff) {
 361        WriteLEUint(0xffffffff);    // Zip64 marker
 362      } else {
 363        WriteLEInt((int)startOfCentralDirectory);
 364      }
 365
 366      int commentLength = (comment != null) ? comment.Length : 0;
 367
 368      if (commentLength > 0xffff) {
 369        throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));
 370      }
 371
 372      WriteLEShort(commentLength);
 373
 374      if (commentLength > 0) {
 375        Write(comment, 0, comment.Length);
 376      }
 377    }
 378
 379    #region LE value reading/writing
 380    /// <summary>
 381    /// Read an unsigned short in little endian byte order.
 382    /// </summary>
 383    /// <returns>Returns the value read.</returns>
 384    /// <exception cref="IOException">
 385    /// An i/o error occurs.
 386    /// </exception>
 387    /// <exception cref="EndOfStreamException">
 388    /// The file ends prematurely
 389    /// </exception>
 390    public int ReadLEShort()
 391    {
 392      int byteValue1 = stream_.ReadByte();
 393
 394      if (byteValue1 < 0) {
 395        throw new EndOfStreamException();
 396      }
 397
 398      int byteValue2 = stream_.ReadByte();
 399      if (byteValue2 < 0) {
 400        throw new EndOfStreamException();
 401      }
 402
 403      return byteValue1 | (byteValue2 << 8);
 404    }
 405
 406    /// <summary>
 407    /// Read an int in little endian byte order.
 408    /// </summary>
 409    /// <returns>Returns the value read.</returns>
 410    /// <exception cref="IOException">
 411    /// An i/o error occurs.
 412    /// </exception>
 413    /// <exception cref="System.IO.EndOfStreamException">
 414    /// The file ends prematurely
 415    /// </exception>
 416    public int ReadLEInt()
 417    {
 418      return ReadLEShort() | (ReadLEShort() << 16);
 419    }
 420
 421    /// <summary>
 422    /// Read a long in little endian byte order.
 423    /// </summary>
 424    /// <returns>The value read.</returns>
 425    public long ReadLELong()
 426    {
 427      return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);
 428    }
 429
 430    /// <summary>
 431    /// Write an unsigned short in little endian byte order.
 432    /// </summary>
 433    /// <param name="value">The value to write.</param>
 434    public void WriteLEShort(int value)
 435    {
 436      stream_.WriteByte((byte)(value & 0xff));
 437      stream_.WriteByte((byte)((value >> 8) & 0xff));
 438    }
 439
 440    /// <summary>
 441    /// Write a ushort in little endian byte order.
 442    /// </summary>
 443    /// <param name="value">The value to write.</param>
 444    public void WriteLEUshort(ushort value)
 445    {
 446      stream_.WriteByte((byte)(value & 0xff));
 447      stream_.WriteByte((byte)(value >> 8));
 448    }
 449
 450    /// <summary>
 451    /// Write an int in little endian byte order.
 452    /// </summary>
 453    /// <param name="value">The value to write.</param>
 454    public void WriteLEInt(int value)
 455    {
 456      WriteLEShort(value);
 457      WriteLEShort(value >> 16);
 458    }
 459
 460    /// <summary>
 461    /// Write a uint in little endian byte order.
 462    /// </summary>
 463    /// <param name="value">The value to write.</param>
 464    public void WriteLEUint(uint value)
 465    {
 466      WriteLEUshort((ushort)(value & 0xffff));
 467      WriteLEUshort((ushort)(value >> 16));
 468    }
 469
 470    /// <summary>
 471    /// Write a long in little endian byte order.
 472    /// </summary>
 473    /// <param name="value">The value to write.</param>
 474    public void WriteLELong(long value)
 475    {
 476      WriteLEInt((int)value);
 477      WriteLEInt((int)(value >> 32));
 478    }
 479
 480    /// <summary>
 481    /// Write a ulong in little endian byte order.
 482    /// </summary>
 483    /// <param name="value">The value to write.</param>
 484    public void WriteLEUlong(ulong value)
 485    {
 486      WriteLEUint((uint)(value & 0xffffffff));
 487      WriteLEUint((uint)(value >> 32));
 488    }
 489
 490    #endregion
 491
 492    /// <summary>
 493    /// Write a data descriptor.
 494    /// </summary>
 495    /// <param name="entry">The entry to write a descriptor for.</param>
 496    /// <returns>Returns the number of descriptor bytes written.</returns>
 497    public int WriteDataDescriptor(ZipEntry entry)
 498    {
 499      if (entry == null) {
 500        throw new ArgumentNullException(nameof(entry));
 501      }
 502
 503      int result = 0;
 504
 505      // Add data descriptor if flagged as required
 506      if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 507        // The signature is not PKZIP originally but is now described as optional
 508        // in the PKZIP Appnote documenting trhe format.
 509        WriteLEInt(ZipConstants.DataDescriptorSignature);
 510        WriteLEInt(unchecked((int)(entry.Crc)));
 511
 512        result += 8;
 513
 514        if (entry.LocalHeaderRequiresZip64) {
 515          WriteLELong(entry.CompressedSize);
 516          WriteLELong(entry.Size);
 517          result += 16;
 518        } else {
 519          WriteLEInt((int)entry.CompressedSize);
 520          WriteLEInt((int)entry.Size);
 521          result += 8;
 522        }
 523      }
 524
 525      return result;
 526    }
 527
 528    /// <summary>
 529    /// Read data descriptor at the end of compressed data.
 530    /// </summary>
 531    /// <param name="zip64">if set to <c>true</c> [zip64].</param>
 532    /// <param name="data">The data to fill in.</param>
 533    /// <returns>Returns the number of bytes read in the descriptor.</returns>
 534    public void ReadDataDescriptor(bool zip64, DescriptorData data)
 535    {
 536      int intValue = ReadLEInt();
 537
 538      // In theory this may not be a descriptor according to PKZIP appnote.
 539      // In practise its always there.
 540      if (intValue != ZipConstants.DataDescriptorSignature) {
 541        throw new ZipException("Data descriptor signature not found");
 542      }
 543
 544      data.Crc = ReadLEInt();
 545
 546      if (zip64) {
 547        data.CompressedSize = ReadLELong();
 548        data.Size = ReadLELong();
 549      } else {
 550        data.CompressedSize = ReadLEInt();
 551        data.Size = ReadLEInt();
 552      }
 553    }
 554
 555    #region Instance Fields
 556    bool isOwner_;
 557    Stream stream_;
 558    #endregion
 559  }
 560}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ExtendedPathFilter.htm b/docs/opencover/ICSharpCode.SharpZipLib_ExtendedPathFilter.htm new file mode 100644 index 000000000..09e74b972 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ExtendedPathFilter.htm @@ -0,0 +1,325 @@ + + + + +ICSharpCode.SharpZipLib.Core.ExtendedPathFilter - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.ExtendedPathFilter
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\PathFilter.cs
Covered lines:0
Uncovered lines:47
Coverable lines:47
Total lines:280
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor(...)100
.ctor(...)100
IsMatch(...)500
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\PathFilter.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Core
 5{
 6  /// <summary>
 7  /// PathFilter filters directories and files using a form of <see cref="System.Text.RegularExpressions.Regex">regular 
 8  /// by full path name.
 9  /// See <see cref="NameFilter">NameFilter</see> for more detail on filtering.
 10  /// </summary>
 11  public class PathFilter : IScanFilter
 12  {
 13    #region Constructors
 14    /// <summary>
 15    /// Initialise a new instance of <see cref="PathFilter"></see>.
 16    /// </summary>
 17    /// <param name="filter">The <see cref="NameFilter">filter</see> expression to apply.</param>
 18    public PathFilter(string filter)
 19    {
 20      nameFilter_ = new NameFilter(filter);
 21    }
 22    #endregion
 23
 24    #region IScanFilter Members
 25    /// <summary>
 26    /// Test a name to see if it matches the filter.
 27    /// </summary>
 28    /// <param name="name">The name to test.</param>
 29    /// <returns>True if the name matches, false otherwise.</returns>
 30    /// <remarks><see cref="Path.GetFullPath(string)"/> is used to get the full path before matching.</remarks>
 31    public virtual bool IsMatch(string name)
 32    {
 33      bool result = false;
 34
 35      if (name != null) {
 36        string cooked = (name.Length > 0) ? Path.GetFullPath(name) : "";
 37        result = nameFilter_.IsMatch(cooked);
 38      }
 39      return result;
 40    }
 41
 42    readonly
 43    #endregion
 44
 45    #region Instance Fields
 46    NameFilter nameFilter_;
 47    #endregion
 48  }
 49
 50  /// <summary>
 51  /// ExtendedPathFilter filters based on name, file size, and the last write time of the file.
 52  /// </summary>
 53  /// <remarks>Provides an example of how to customise filtering.</remarks>
 54  public class ExtendedPathFilter : PathFilter
 55  {
 56    #region Constructors
 57    /// <summary>
 58    /// Initialise a new instance of ExtendedPathFilter.
 59    /// </summary>
 60    /// <param name="filter">The filter to apply.</param>
 61    /// <param name="minSize">The minimum file size to include.</param>
 62    /// <param name="maxSize">The maximum file size to include.</param>
 63    public ExtendedPathFilter(string filter,
 64      long minSize, long maxSize)
 065      : base(filter)
 66    {
 067      MinSize = minSize;
 068      MaxSize = maxSize;
 069    }
 70
 71    /// <summary>
 72    /// Initialise a new instance of ExtendedPathFilter.
 73    /// </summary>
 74    /// <param name="filter">The filter to apply.</param>
 75    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
 76    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
 77    public ExtendedPathFilter(string filter,
 78      DateTime minDate, DateTime maxDate)
 079      : base(filter)
 80    {
 081      MinDate = minDate;
 082      MaxDate = maxDate;
 083    }
 84
 85    /// <summary>
 86    /// Initialise a new instance of ExtendedPathFilter.
 87    /// </summary>
 88    /// <param name="filter">The filter to apply.</param>
 89    /// <param name="minSize">The minimum file size to include.</param>
 90    /// <param name="maxSize">The maximum file size to include.</param>
 91    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
 92    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
 93    public ExtendedPathFilter(string filter,
 94      long minSize, long maxSize,
 95      DateTime minDate, DateTime maxDate)
 096      : base(filter)
 97    {
 098      MinSize = minSize;
 099      MaxSize = maxSize;
 0100      MinDate = minDate;
 0101      MaxDate = maxDate;
 0102    }
 103    #endregion
 104
 105    #region IScanFilter Members
 106    /// <summary>
 107    /// Test a filename to see if it matches the filter.
 108    /// </summary>
 109    /// <param name="name">The filename to test.</param>
 110    /// <returns>True if the filter matches, false otherwise.</returns>
 111    /// <exception cref="System.IO.FileNotFoundException">The <see paramref="fileName"/> doesnt exist</exception>
 112    public override bool IsMatch(string name)
 113    {
 0114      bool result = base.IsMatch(name);
 115
 0116       if (result) {
 0117        var fileInfo = new FileInfo(name);
 0118        result =
 0119          (MinSize <= fileInfo.Length) &&
 0120          (MaxSize >= fileInfo.Length) &&
 0121          (MinDate <= fileInfo.LastWriteTime) &&
 0122          (MaxDate >= fileInfo.LastWriteTime)
 0123          ;
 124      }
 0125      return result;
 126    }
 127    #endregion
 128
 129    #region Properties
 130    /// <summary>
 131    /// Get/set the minimum size/length for a file that will match this filter.
 132    /// </summary>
 133    /// <remarks>The default value is zero.</remarks>
 134    /// <exception cref="ArgumentOutOfRangeException">value is less than zero; greater than <see cref="MaxSize"/></excep
 135    public long MinSize {
 0136      get { return minSize_; }
 137      set {
 0138         if ((value < 0) || (maxSize_ < value)) {
 0139          throw new ArgumentOutOfRangeException(nameof(value));
 140        }
 141
 0142        minSize_ = value;
 0143      }
 144    }
 145
 146    /// <summary>
 147    /// Get/set the maximum size/length for a file that will match this filter.
 148    /// </summary>
 149    /// <remarks>The default value is <see cref="System.Int64.MaxValue"/></remarks>
 150    /// <exception cref="ArgumentOutOfRangeException">value is less than zero or less than <see cref="MinSize"/></except
 151    public long MaxSize {
 0152      get { return maxSize_; }
 153      set {
 0154         if ((value < 0) || (minSize_ > value)) {
 0155          throw new ArgumentOutOfRangeException(nameof(value));
 156        }
 157
 0158        maxSize_ = value;
 0159      }
 160    }
 161
 162    /// <summary>
 163    /// Get/set the minimum <see cref="DateTime"/> value that will match for this filter.
 164    /// </summary>
 165    /// <remarks>Files with a LastWrite time less than this value are excluded by the filter.</remarks>
 166    public DateTime MinDate {
 167      get {
 0168        return minDate_;
 169      }
 170
 171      set {
 0172         if (value > maxDate_) {
 0173          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MaxDate");
 174        }
 175
 0176        minDate_ = value;
 0177      }
 178    }
 179
 180    /// <summary>
 181    /// Get/set the maximum <see cref="DateTime"/> value that will match for this filter.
 182    /// </summary>
 183    /// <remarks>Files with a LastWrite time greater than this value are excluded by the filter.</remarks>
 184    public DateTime MaxDate {
 185      get {
 0186        return maxDate_;
 187      }
 188
 189      set {
 0190         if (minDate_ > value) {
 0191          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MinDate");
 192        }
 193
 0194        maxDate_ = value;
 0195      }
 196    }
 197    #endregion
 198
 199    #region Instance Fields
 200    long minSize_;
 0201    long maxSize_ = long.MaxValue;
 0202    DateTime minDate_ = DateTime.MinValue;
 0203    DateTime maxDate_ = DateTime.MaxValue;
 204    #endregion
 205  }
 206
 207  /// <summary>
 208  /// NameAndSizeFilter filters based on name and file size.
 209  /// </summary>
 210  /// <remarks>A sample showing how filters might be extended.</remarks>
 211  [Obsolete("Use ExtendedPathFilter instead")]
 212  public class NameAndSizeFilter : PathFilter
 213  {
 214
 215    /// <summary>
 216    /// Initialise a new instance of NameAndSizeFilter.
 217    /// </summary>
 218    /// <param name="filter">The filter to apply.</param>
 219    /// <param name="minSize">The minimum file size to include.</param>
 220    /// <param name="maxSize">The maximum file size to include.</param>
 221    public NameAndSizeFilter(string filter, long minSize, long maxSize)
 222      : base(filter)
 223    {
 224      MinSize = minSize;
 225      MaxSize = maxSize;
 226    }
 227
 228    /// <summary>
 229    /// Test a filename to see if it matches the filter.
 230    /// </summary>
 231    /// <param name="name">The filename to test.</param>
 232    /// <returns>True if the filter matches, false otherwise.</returns>
 233    public override bool IsMatch(string name)
 234    {
 235      bool result = base.IsMatch(name);
 236
 237      if (result) {
 238        var fileInfo = new FileInfo(name);
 239        long length = fileInfo.Length;
 240        result =
 241          (MinSize <= length) &&
 242          (MaxSize >= length);
 243      }
 244      return result;
 245    }
 246
 247    /// <summary>
 248    /// Get/set the minimum size for a file that will match this filter.
 249    /// </summary>
 250    public long MinSize {
 251      get { return minSize_; }
 252      set {
 253        if ((value < 0) || (maxSize_ < value)) {
 254          throw new ArgumentOutOfRangeException(nameof(value));
 255        }
 256
 257        minSize_ = value;
 258      }
 259    }
 260
 261    /// <summary>
 262    /// Get/set the maximum size for a file that will match this filter.
 263    /// </summary>
 264    public long MaxSize {
 265      get { return maxSize_; }
 266      set {
 267        if ((value < 0) || (minSize_ > value)) {
 268          throw new ArgumentOutOfRangeException(nameof(value));
 269        }
 270
 271        maxSize_ = value;
 272      }
 273    }
 274
 275    #region Instance Fields
 276    long minSize_;
 277    long maxSize_ = long.MaxValue;
 278    #endregion
 279  }
 280}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ExtendedUnixData.htm b/docs/opencover/ICSharpCode.SharpZipLib_ExtendedUnixData.htm new file mode 100644 index 000000000..bf33abe79 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ExtendedUnixData.htm @@ -0,0 +1,941 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ExtendedUnixData - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ExtendedUnixData
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipExtraData.cs
Covered lines:32
Uncovered lines:30
Coverable lines:62
Total lines:896
Line coverage:51.6%
Branch coverage:30%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
SetData(...)756.2533.33
GetData()666.6757.14
IsValidValue(...)2100100
.ctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipExtraData.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Zip
 5{
 6  // TODO: Sort out wether tagged data is useful and what a good implementation might look like.
 7  // Its just a sketch of an idea at the moment.
 8
 9  /// <summary>
 10  /// ExtraData tagged value interface.
 11  /// </summary>
 12  public interface ITaggedData
 13  {
 14    /// <summary>
 15    /// Get the ID for this tagged data value.
 16    /// </summary>
 17    short TagID { get; }
 18
 19    /// <summary>
 20    /// Set the contents of this instance from the data passed.
 21    /// </summary>
 22    /// <param name="data">The data to extract contents from.</param>
 23    /// <param name="offset">The offset to begin extracting data from.</param>
 24    /// <param name="count">The number of bytes to extract.</param>
 25    void SetData(byte[] data, int offset, int count);
 26
 27    /// <summary>
 28    /// Get the data representing this instance.
 29    /// </summary>
 30    /// <returns>Returns the data for this instance.</returns>
 31    byte[] GetData();
 32  }
 33
 34  /// <summary>
 35  /// A raw binary tagged value
 36  /// </summary>
 37  public class RawTaggedData : ITaggedData
 38  {
 39    /// <summary>
 40    /// Initialise a new instance.
 41    /// </summary>
 42    /// <param name="tag">The tag ID.</param>
 43    public RawTaggedData(short tag)
 44    {
 45      _tag = tag;
 46    }
 47
 48    #region ITaggedData Members
 49
 50    /// <summary>
 51    /// Get the ID for this tagged data value.
 52    /// </summary>
 53    public short TagID {
 54      get { return _tag; }
 55      set { _tag = value; }
 56    }
 57
 58    /// <summary>
 59    /// Set the data from the raw values provided.
 60    /// </summary>
 61    /// <param name="data">The raw data to extract values from.</param>
 62    /// <param name="offset">The index to start extracting values from.</param>
 63    /// <param name="count">The number of bytes available.</param>
 64    public void SetData(byte[] data, int offset, int count)
 65    {
 66      if (data == null) {
 67        throw new ArgumentNullException(nameof(data));
 68      }
 69
 70      _data = new byte[count];
 71      Array.Copy(data, offset, _data, 0, count);
 72    }
 73
 74    /// <summary>
 75    /// Get the binary data representing this instance.
 76    /// </summary>
 77    /// <returns>The raw binary data representing this instance.</returns>
 78    public byte[] GetData()
 79    {
 80      return _data;
 81    }
 82
 83    #endregion
 84
 85    /// <summary>
 86    /// Get /set the binary data representing this instance.
 87    /// </summary>
 88    /// <returns>The raw binary data representing this instance.</returns>
 89    public byte[] Data {
 90      get { return _data; }
 91      set { _data = value; }
 92    }
 93
 94    #region Instance Fields
 95    /// <summary>
 96    /// The tag ID for this instance.
 97    /// </summary>
 98    short _tag;
 99
 100    byte[] _data;
 101    #endregion
 102  }
 103
 104  /// <summary>
 105  /// Class representing extended unix date time values.
 106  /// </summary>
 107  public class ExtendedUnixData : ITaggedData
 108  {
 109    /// <summary>
 110    /// Flags indicate which values are included in this instance.
 111    /// </summary>
 112    [Flags]
 113    public enum Flags : byte
 114    {
 115      /// <summary>
 116      /// The modification time is included
 117      /// </summary>
 118      ModificationTime = 0x01,
 119
 120      /// <summary>
 121      /// The access time is included
 122      /// </summary>
 123      AccessTime = 0x02,
 124
 125      /// <summary>
 126      /// The create time is included.
 127      /// </summary>
 128      CreateTime = 0x04,
 129    }
 130
 131    #region ITaggedData Members
 132
 133    /// <summary>
 134    /// Get the ID
 135    /// </summary>
 136    public short TagID {
 66038137      get { return 0x5455; }
 138    }
 139
 140    /// <summary>
 141    /// Set the data from the raw values provided.
 142    /// </summary>
 143    /// <param name="data">The raw data to extract values from.</param>
 144    /// <param name="index">The index to start extracting values from.</param>
 145    /// <param name="count">The number of bytes available.</param>
 146    public void SetData(byte[] data, int index, int count)
 147    {
 1148      using (MemoryStream ms = new MemoryStream(data, index, count, false))
 1149      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 150        // bit 0           if set, modification time is present
 151        // bit 1           if set, access time is present
 152        // bit 2           if set, creation time is present
 153
 1154        _flags = (Flags)helperStream.ReadByte();
 1155         if (((_flags & Flags.ModificationTime) != 0))
 156        {
 1157          int iTime = helperStream.ReadLEInt();
 158
 1159          _modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 1160            new TimeSpan(0, 0, 0, iTime, 0);
 161
 162          // Central-header version is truncated after modification time
 2163           if (count <= 5) return;
 164        }
 165
 0166         if ((_flags & Flags.AccessTime) != 0) {
 0167          int iTime = helperStream.ReadLEInt();
 168
 0169          _lastAccessTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 0170            new TimeSpan(0, 0, 0, iTime, 0);
 171        }
 172
 0173         if ((_flags & Flags.CreateTime) != 0) {
 0174          int iTime = helperStream.ReadLEInt();
 175
 0176          _createTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 0177            new TimeSpan(0, 0, 0, iTime, 0);
 178        }
 0179      }
 1180    }
 181
 182    /// <summary>
 183    /// Get the binary data representing this instance.
 184    /// </summary>
 185    /// <returns>The raw binary data representing this instance.</returns>
 186    public byte[] GetData()
 187    {
 1188      using (MemoryStream ms = new MemoryStream())
 1189      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 1190        helperStream.IsStreamOwner = false;
 1191        helperStream.WriteByte((byte)_flags);     // Flags
 1192         if ((_flags & Flags.ModificationTime) != 0) {
 1193          TimeSpan span = _modificationTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 1194          var seconds = (int)span.TotalSeconds;
 1195          helperStream.WriteLEInt(seconds);
 196        }
 1197         if ((_flags & Flags.AccessTime) != 0) {
 0198          TimeSpan span = _lastAccessTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 0199          var seconds = (int)span.TotalSeconds;
 0200          helperStream.WriteLEInt(seconds);
 201        }
 1202         if ((_flags & Flags.CreateTime) != 0) {
 0203          TimeSpan span = _createTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 0204          var seconds = (int)span.TotalSeconds;
 0205          helperStream.WriteLEInt(seconds);
 206        }
 1207        return ms.ToArray();
 208      }
 1209    }
 210
 211    #endregion
 212
 213    /// <summary>
 214    /// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>
 215    /// </summary>
 216    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 217    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 218    /// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,
 219    /// which is the number of seconds since 1970-01-01.
 220    /// Being 32 bits means the values here cover a range of about 136 years.
 221    /// The minimum representable time is 1901-12-13 20:45:52,
 222    /// and the maximum representable time is 2038-01-19 03:14:07.
 223    /// </remarks>
 224    public static bool IsValidValue(DateTime value)
 225    {
 2226      return ((value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||
 2227          (value <= new DateTime(2038, 1, 19, 03, 14, 07)));
 228    }
 229
 230    /// <summary>
 231    /// Get /set the Modification Time
 232    /// </summary>
 233    /// <exception cref="ArgumentOutOfRangeException"></exception>
 234    /// <seealso cref="IsValidValue"></seealso>
 235    public DateTime ModificationTime {
 4236      get { return _modificationTime; }
 237      set {
 2238         if (!IsValidValue(value)) {
 0239          throw new ArgumentOutOfRangeException(nameof(value));
 240        }
 241
 2242        _flags |= Flags.ModificationTime;
 2243        _modificationTime = value;
 2244      }
 245    }
 246
 247    /// <summary>
 248    /// Get / set the Access Time
 249    /// </summary>
 250    /// <exception cref="ArgumentOutOfRangeException"></exception>
 251    /// <seealso cref="IsValidValue"></seealso>
 252    public DateTime AccessTime {
 0253      get { return _lastAccessTime; }
 254      set {
 0255         if (!IsValidValue(value)) {
 0256          throw new ArgumentOutOfRangeException(nameof(value));
 257        }
 258
 0259        _flags |= Flags.AccessTime;
 0260        _lastAccessTime = value;
 0261      }
 262    }
 263
 264    /// <summary>
 265    /// Get / Set the Create Time
 266    /// </summary>
 267    /// <exception cref="ArgumentOutOfRangeException"></exception>
 268    /// <seealso cref="IsValidValue"></seealso>
 269    public DateTime CreateTime {
 0270      get { return _createTime; }
 271      set {
 0272         if (!IsValidValue(value)) {
 0273          throw new ArgumentOutOfRangeException(nameof(value));
 274        }
 275
 0276        _flags |= Flags.CreateTime;
 0277        _createTime = value;
 0278      }
 279    }
 280
 281    /// <summary>
 282    /// Get/set the <see cref="Flags">values</see> to include.
 283    /// </summary>
 284    public Flags Include
 285    {
 0286      get { return _flags; }
 0287      set { _flags = value; }
 288    }
 289
 290    #region Instance Fields
 291    Flags _flags;
 66038292    DateTime _modificationTime = new DateTime(1970, 1, 1);
 66038293    DateTime _lastAccessTime = new DateTime(1970, 1, 1);
 66038294    DateTime _createTime = new DateTime(1970, 1, 1);
 295    #endregion
 296  }
 297
 298  /// <summary>
 299  /// Class handling NT date time values.
 300  /// </summary>
 301  public class NTTaggedData : ITaggedData
 302  {
 303    /// <summary>
 304    /// Get the ID for this tagged data value.
 305    /// </summary>
 306    public short TagID {
 307      get { return 10; }
 308    }
 309
 310    /// <summary>
 311    /// Set the data from the raw values provided.
 312    /// </summary>
 313    /// <param name="data">The raw data to extract values from.</param>
 314    /// <param name="index">The index to start extracting values from.</param>
 315    /// <param name="count">The number of bytes available.</param>
 316    public void SetData(byte[] data, int index, int count)
 317    {
 318      using (MemoryStream ms = new MemoryStream(data, index, count, false))
 319      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 320        helperStream.ReadLEInt(); // Reserved
 321        while (helperStream.Position < helperStream.Length) {
 322          int ntfsTag = helperStream.ReadLEShort();
 323          int ntfsLength = helperStream.ReadLEShort();
 324          if (ntfsTag == 1) {
 325            if (ntfsLength >= 24) {
 326              long lastModificationTicks = helperStream.ReadLELong();
 327              _lastModificationTime = DateTime.FromFileTimeUtc(lastModificationTicks);
 328
 329              long lastAccessTicks = helperStream.ReadLELong();
 330              _lastAccessTime = DateTime.FromFileTimeUtc(lastAccessTicks);
 331
 332              long createTimeTicks = helperStream.ReadLELong();
 333              _createTime = DateTime.FromFileTimeUtc(createTimeTicks);
 334            }
 335            break;
 336          } else {
 337            // An unknown NTFS tag so simply skip it.
 338            helperStream.Seek(ntfsLength, SeekOrigin.Current);
 339          }
 340        }
 341      }
 342    }
 343
 344    /// <summary>
 345    /// Get the binary data representing this instance.
 346    /// </summary>
 347    /// <returns>The raw binary data representing this instance.</returns>
 348    public byte[] GetData()
 349    {
 350      using (MemoryStream ms = new MemoryStream())
 351      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 352        helperStream.IsStreamOwner = false;
 353        helperStream.WriteLEInt(0);       // Reserved
 354        helperStream.WriteLEShort(1);     // Tag
 355        helperStream.WriteLEShort(24);    // Length = 3 x 8.
 356        helperStream.WriteLELong(_lastModificationTime.ToFileTimeUtc());
 357        helperStream.WriteLELong(_lastAccessTime.ToFileTimeUtc());
 358        helperStream.WriteLELong(_createTime.ToFileTimeUtc());
 359        return ms.ToArray();
 360      }
 361    }
 362
 363    /// <summary>
 364    /// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>
 365    /// </summary>
 366    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 367    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 368    /// <remarks>
 369    /// NTFS filetimes are 64-bit unsigned integers, stored in Intel
 370    /// (least significant byte first) byte order. They determine the
 371    /// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
 372    /// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit
 373    /// </remarks>
 374    public static bool IsValidValue(DateTime value)
 375    {
 376      bool result = true;
 377      try {
 378        value.ToFileTimeUtc();
 379      } catch {
 380        result = false;
 381      }
 382      return result;
 383    }
 384
 385    /// <summary>
 386    /// Get/set the <see cref="DateTime">last modification time</see>.
 387    /// </summary>
 388    public DateTime LastModificationTime {
 389      get { return _lastModificationTime; }
 390      set {
 391        if (!IsValidValue(value)) {
 392          throw new ArgumentOutOfRangeException(nameof(value));
 393        }
 394        _lastModificationTime = value;
 395      }
 396    }
 397
 398    /// <summary>
 399    /// Get /set the <see cref="DateTime">create time</see>
 400    /// </summary>
 401    public DateTime CreateTime {
 402      get { return _createTime; }
 403      set {
 404        if (!IsValidValue(value)) {
 405          throw new ArgumentOutOfRangeException(nameof(value));
 406        }
 407        _createTime = value;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Get /set the <see cref="DateTime">last access time</see>.
 413    /// </summary>
 414    public DateTime LastAccessTime {
 415      get { return _lastAccessTime; }
 416      set {
 417        if (!IsValidValue(value)) {
 418          throw new ArgumentOutOfRangeException(nameof(value));
 419        }
 420        _lastAccessTime = value;
 421      }
 422    }
 423
 424    #region Instance Fields
 425    DateTime _lastAccessTime = DateTime.FromFileTimeUtc(0);
 426    DateTime _lastModificationTime = DateTime.FromFileTimeUtc(0);
 427    DateTime _createTime = DateTime.FromFileTimeUtc(0);
 428    #endregion
 429  }
 430
 431  /// <summary>
 432  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.
 433  /// </summary>
 434  interface ITaggedDataFactory
 435  {
 436    /// <summary>
 437    /// Get data for a specific tag value.
 438    /// </summary>
 439    /// <param name="tag">The tag ID to find.</param>
 440    /// <param name="data">The data to search.</param>
 441    /// <param name="offset">The offset to begin extracting data from.</param>
 442    /// <param name="count">The number of bytes to extract.</param>
 443    /// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>
 444    ITaggedData Create(short tag, byte[] data, int offset, int count);
 445  }
 446
 447  ///
 448  /// <summary>
 449  /// A class to handle the extra data field for Zip entries
 450  /// </summary>
 451  /// <remarks>
 452  /// Extra data contains 0 or more values each prefixed by a header tag and length.
 453  /// They contain zero or more bytes of actual data.
 454  /// The data is held internally using a copy on write strategy.  This is more efficient but
 455  /// means that for extra data created by passing in data can have the values modified by the caller
 456  /// in some circumstances.
 457  /// </remarks>
 458  sealed public class ZipExtraData : IDisposable
 459  {
 460    #region Constructors
 461    /// <summary>
 462    /// Initialise a default instance.
 463    /// </summary>
 464    public ZipExtraData()
 465    {
 466      Clear();
 467    }
 468
 469    /// <summary>
 470    /// Initialise with known extra data.
 471    /// </summary>
 472    /// <param name="data">The extra data.</param>
 473    public ZipExtraData(byte[] data)
 474    {
 475      if (data == null) {
 476        _data = new byte[0];
 477      } else {
 478        _data = data;
 479      }
 480    }
 481    #endregion
 482
 483    /// <summary>
 484    /// Get the raw extra data value
 485    /// </summary>
 486    /// <returns>Returns the raw byte[] extra data this instance represents.</returns>
 487    public byte[] GetEntryData()
 488    {
 489      if (Length > ushort.MaxValue) {
 490        throw new ZipException("Data exceeds maximum length");
 491      }
 492
 493      return (byte[])_data.Clone();
 494    }
 495
 496    /// <summary>
 497    /// Clear the stored data.
 498    /// </summary>
 499    public void Clear()
 500    {
 501      if ((_data == null) || (_data.Length != 0)) {
 502        _data = new byte[0];
 503      }
 504    }
 505
 506    /// <summary>
 507    /// Gets the current extra data length.
 508    /// </summary>
 509    public int Length {
 510      get { return _data.Length; }
 511    }
 512
 513    /// <summary>
 514    /// Get a read-only <see cref="Stream"/> for the associated tag.
 515    /// </summary>
 516    /// <param name="tag">The tag to locate data for.</param>
 517    /// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>
 518    public Stream GetStreamForTag(int tag)
 519    {
 520      Stream result = null;
 521      if (Find(tag)) {
 522        result = new MemoryStream(_data, _index, _readValueLength, false);
 523      }
 524      return result;
 525    }
 526
 527    /// <summary>
 528    /// Get the <see cref="ITaggedData">tagged data</see> for a tag.
 529    /// </summary>
 530    /// <typeparam name="T">The tag to search for.</typeparam>
 531    /// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>
 532    public T GetData<T>()
 533      where T : class, ITaggedData, new()
 534    {
 535      T result = new T();
 536      if (Find(result.TagID))
 537      {
 538        result.SetData(_data, _readValueStart, _readValueLength);
 539        return result;
 540      }
 541      else return null;
 542    }
 543
 544    /// <summary>
 545    /// Get the length of the last value found by <see cref="Find"/>
 546    /// </summary>
 547    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.</remarks>
 548    public int ValueLength {
 549      get { return _readValueLength; }
 550    }
 551
 552    /// <summary>
 553    /// Get the index for the current read value.
 554    /// </summary>
 555    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.
 556    /// Initially the result will be the index of the first byte of actual data.  The value is updated after calls to
 557    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>
 558    public int CurrentReadIndex {
 559      get { return _index; }
 560    }
 561
 562    /// <summary>
 563    /// Get the number of bytes remaining to be read for the current value;
 564    /// </summary>
 565    public int UnreadCount {
 566      get {
 567        if ((_readValueStart > _data.Length) ||
 568          (_readValueStart < 4)) {
 569          throw new ZipException("Find must be called before calling a Read method");
 570        }
 571
 572        return _readValueStart + _readValueLength - _index;
 573      }
 574    }
 575
 576    /// <summary>
 577    /// Find an extra data value
 578    /// </summary>
 579    /// <param name="headerID">The identifier for the value to find.</param>
 580    /// <returns>Returns true if the value was found; false otherwise.</returns>
 581    public bool Find(int headerID)
 582    {
 583      _readValueStart = _data.Length;
 584      _readValueLength = 0;
 585      _index = 0;
 586
 587      int localLength = _readValueStart;
 588      int localTag = headerID - 1;
 589
 590      // Trailing bytes that cant make up an entry (as there arent enough
 591      // bytes for a tag and length) are ignored!
 592      while ((localTag != headerID) && (_index < _data.Length - 3)) {
 593        localTag = ReadShortInternal();
 594        localLength = ReadShortInternal();
 595        if (localTag != headerID) {
 596          _index += localLength;
 597        }
 598      }
 599
 600      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);
 601
 602      if (result) {
 603        _readValueStart = _index;
 604        _readValueLength = localLength;
 605      }
 606
 607      return result;
 608    }
 609
 610    /// <summary>
 611    /// Add a new entry to extra data.
 612    /// </summary>
 613    /// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>
 614    public void AddEntry(ITaggedData taggedData)
 615    {
 616      if (taggedData == null) {
 617        throw new ArgumentNullException(nameof(taggedData));
 618      }
 619      AddEntry(taggedData.TagID, taggedData.GetData());
 620    }
 621
 622    /// <summary>
 623    /// Add a new entry to extra data
 624    /// </summary>
 625    /// <param name="headerID">The ID for this entry.</param>
 626    /// <param name="fieldData">The data to add.</param>
 627    /// <remarks>If the ID already exists its contents are replaced.</remarks>
 628    public void AddEntry(int headerID, byte[] fieldData)
 629    {
 630      if ((headerID > ushort.MaxValue) || (headerID < 0)) {
 631        throw new ArgumentOutOfRangeException(nameof(headerID));
 632      }
 633
 634      int addLength = (fieldData == null) ? 0 : fieldData.Length;
 635
 636      if (addLength > ushort.MaxValue) {
 637        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");
 638      }
 639
 640      // Test for new length before adjusting data.
 641      int newLength = _data.Length + addLength + 4;
 642
 643      if (Find(headerID)) {
 644        newLength -= (ValueLength + 4);
 645      }
 646
 647      if (newLength > ushort.MaxValue) {
 648        throw new ZipException("Data exceeds maximum length");
 649      }
 650
 651      Delete(headerID);
 652
 653      byte[] newData = new byte[newLength];
 654      _data.CopyTo(newData, 0);
 655      int index = _data.Length;
 656      _data = newData;
 657      SetShort(ref index, headerID);
 658      SetShort(ref index, addLength);
 659      if (fieldData != null) {
 660        fieldData.CopyTo(newData, index);
 661      }
 662    }
 663
 664    /// <summary>
 665    /// Start adding a new entry.
 666    /// </summary>
 667    /// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see
 668    /// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>
 669    /// <seealso cref="AddEntry(ITaggedData)"/>
 670    public void StartNewEntry()
 671    {
 672      _newEntry = new MemoryStream();
 673    }
 674
 675    /// <summary>
 676    /// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.
 677    /// </summary>
 678    /// <param name="headerID">The identifier to use for this entry.</param>
 679    public void AddNewEntry(int headerID)
 680    {
 681      byte[] newData = _newEntry.ToArray();
 682      _newEntry = null;
 683      AddEntry(headerID, newData);
 684    }
 685
 686    /// <summary>
 687    /// Add a byte of data to the pending new entry.
 688    /// </summary>
 689    /// <param name="data">The byte to add.</param>
 690    /// <seealso cref="StartNewEntry"/>
 691    public void AddData(byte data)
 692    {
 693      _newEntry.WriteByte(data);
 694    }
 695
 696    /// <summary>
 697    /// Add data to a pending new entry.
 698    /// </summary>
 699    /// <param name="data">The data to add.</param>
 700    /// <seealso cref="StartNewEntry"/>
 701    public void AddData(byte[] data)
 702    {
 703      if (data == null) {
 704        throw new ArgumentNullException(nameof(data));
 705      }
 706
 707      _newEntry.Write(data, 0, data.Length);
 708    }
 709
 710    /// <summary>
 711    /// Add a short value in little endian order to the pending new entry.
 712    /// </summary>
 713    /// <param name="toAdd">The data to add.</param>
 714    /// <seealso cref="StartNewEntry"/>
 715    public void AddLeShort(int toAdd)
 716    {
 717      unchecked {
 718        _newEntry.WriteByte((byte)toAdd);
 719        _newEntry.WriteByte((byte)(toAdd >> 8));
 720      }
 721    }
 722
 723    /// <summary>
 724    /// Add an integer value in little endian order to the pending new entry.
 725    /// </summary>
 726    /// <param name="toAdd">The data to add.</param>
 727    /// <seealso cref="StartNewEntry"/>
 728    public void AddLeInt(int toAdd)
 729    {
 730      unchecked {
 731        AddLeShort((short)toAdd);
 732        AddLeShort((short)(toAdd >> 16));
 733      }
 734    }
 735
 736    /// <summary>
 737    /// Add a long value in little endian order to the pending new entry.
 738    /// </summary>
 739    /// <param name="toAdd">The data to add.</param>
 740    /// <seealso cref="StartNewEntry"/>
 741    public void AddLeLong(long toAdd)
 742    {
 743      unchecked {
 744        AddLeInt((int)(toAdd & 0xffffffff));
 745        AddLeInt((int)(toAdd >> 32));
 746      }
 747    }
 748
 749    /// <summary>
 750    /// Delete an extra data field.
 751    /// </summary>
 752    /// <param name="headerID">The identifier of the field to delete.</param>
 753    /// <returns>Returns true if the field was found and deleted.</returns>
 754    public bool Delete(int headerID)
 755    {
 756      bool result = false;
 757
 758      if (Find(headerID)) {
 759        result = true;
 760        int trueStart = _readValueStart - 4;
 761
 762        byte[] newData = new byte[_data.Length - (ValueLength + 4)];
 763        Array.Copy(_data, 0, newData, 0, trueStart);
 764
 765        int trueEnd = trueStart + ValueLength + 4;
 766        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);
 767        _data = newData;
 768      }
 769      return result;
 770    }
 771
 772    #region Reading Support
 773    /// <summary>
 774    /// Read a long in little endian form from the last <see cref="Find">found</see> data value
 775    /// </summary>
 776    /// <returns>Returns the long value read.</returns>
 777    public long ReadLong()
 778    {
 779      ReadCheck(8);
 780      return (ReadInt() & 0xffffffff) | (((long)ReadInt()) << 32);
 781    }
 782
 783    /// <summary>
 784    /// Read an integer in little endian form from the last <see cref="Find">found</see> data value.
 785    /// </summary>
 786    /// <returns>Returns the integer read.</returns>
 787    public int ReadInt()
 788    {
 789      ReadCheck(4);
 790
 791      int result = _data[_index] + (_data[_index + 1] << 8) +
 792        (_data[_index + 2] << 16) + (_data[_index + 3] << 24);
 793      _index += 4;
 794      return result;
 795    }
 796
 797    /// <summary>
 798    /// Read a short value in little endian form from the last <see cref="Find">found</see> data value.
 799    /// </summary>
 800    /// <returns>Returns the short value read.</returns>
 801    public int ReadShort()
 802    {
 803      ReadCheck(2);
 804      int result = _data[_index] + (_data[_index + 1] << 8);
 805      _index += 2;
 806      return result;
 807    }
 808
 809    /// <summary>
 810    /// Read a byte from an extra data
 811    /// </summary>
 812    /// <returns>The byte value read or -1 if the end of data has been reached.</returns>
 813    public int ReadByte()
 814    {
 815      int result = -1;
 816      if ((_index < _data.Length) && (_readValueStart + _readValueLength > _index)) {
 817        result = _data[_index];
 818        _index += 1;
 819      }
 820      return result;
 821    }
 822
 823    /// <summary>
 824    /// Skip data during reading.
 825    /// </summary>
 826    /// <param name="amount">The number of bytes to skip.</param>
 827    public void Skip(int amount)
 828    {
 829      ReadCheck(amount);
 830      _index += amount;
 831    }
 832
 833    void ReadCheck(int length)
 834    {
 835      if ((_readValueStart > _data.Length) ||
 836        (_readValueStart < 4)) {
 837        throw new ZipException("Find must be called before calling a Read method");
 838      }
 839
 840      if (_index > _readValueStart + _readValueLength - length) {
 841        throw new ZipException("End of extra data");
 842      }
 843
 844      if (_index + length < 4) {
 845        throw new ZipException("Cannot read before start of tag");
 846      }
 847    }
 848
 849    /// <summary>
 850    /// Internal form of <see cref="ReadShort"/> that reads data at any location.
 851    /// </summary>
 852    /// <returns>Returns the short value read.</returns>
 853    int ReadShortInternal()
 854    {
 855      if (_index > _data.Length - 2) {
 856        throw new ZipException("End of extra data");
 857      }
 858
 859      int result = _data[_index] + (_data[_index + 1] << 8);
 860      _index += 2;
 861      return result;
 862    }
 863
 864    void SetShort(ref int index, int source)
 865    {
 866      _data[index] = (byte)source;
 867      _data[index + 1] = (byte)(source >> 8);
 868      index += 2;
 869    }
 870
 871    #endregion
 872
 873    #region IDisposable Members
 874
 875    /// <summary>
 876    /// Dispose of this instance.
 877    /// </summary>
 878    public void Dispose()
 879    {
 880      if (_newEntry != null) {
 881        _newEntry.Close();
 882      }
 883    }
 884
 885    #endregion
 886
 887    #region Instance Fields
 888    int _index;
 889    int _readValueStart;
 890    int _readValueLength;
 891
 892    MemoryStream _newEntry;
 893    byte[] _data;
 894    #endregion
 895  }
 896}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_FastZip.htm b/docs/opencover/ICSharpCode.SharpZipLib_FastZip.htm new file mode 100644 index 000000000..dee5d59d8 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_FastZip.htm @@ -0,0 +1,704 @@ + + + + +ICSharpCode.SharpZipLib.Zip.FastZip - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.FastZip
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\FastZip.cs
Covered lines:85
Uncovered lines:99
Coverable lines:184
Total lines:648
Line coverage:46.1%
Branch coverage:28.3%
+

Metrics

+ + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
.ctor(...)100
CreateZip(...)100
CreateZip(...)100
CreateZip(...)772.2245.45
ExtractZip(...)1100100
ExtractZip(...)1100100
ExtractZip(...)138047.83
ProcessDirectory(...)600
ProcessFile(...)652.9444.44
AddFileContents(...)663.6454.55
ExtractFileEntry(...)1800
ExtractEntry(...)1454.5544.44
MakeExternalAttributes(...)100
NameIsValid(...)200
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\FastZip.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using ICSharpCode.SharpZipLib.Core;
 4
 5namespace ICSharpCode.SharpZipLib.Zip
 6{
 7  /// <summary>
 8  /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.
 9  /// </summary>
 10  public class FastZipEvents
 11  {
 12    /// <summary>
 13    /// Delegate to invoke when processing directories.
 14    /// </summary>
 15    public event EventHandler<DirectoryEventArgs> ProcessDirectory;
 16
 17    /// <summary>
 18    /// Delegate to invoke when processing files.
 19    /// </summary>
 20    public ProcessFileHandler ProcessFile;
 21
 22    /// <summary>
 23    /// Delegate to invoke during processing of files.
 24    /// </summary>
 25    public ProgressHandler Progress;
 26
 27    /// <summary>
 28    /// Delegate to invoke when processing for a file has been completed.
 29    /// </summary>
 30    public CompletedFileHandler CompletedFile;
 31
 32    /// <summary>
 33    /// Delegate to invoke when processing directory failures.
 34    /// </summary>
 35    public DirectoryFailureHandler DirectoryFailure;
 36
 37    /// <summary>
 38    /// Delegate to invoke when processing file failures.
 39    /// </summary>
 40    public FileFailureHandler FileFailure;
 41
 42    /// <summary>
 43    /// Raise the <see cref="DirectoryFailure">directory failure</see> event.
 44    /// </summary>
 45    /// <param name="directory">The directory causing the failure.</param>
 46    /// <param name="e">The exception for this event.</param>
 47    /// <returns>A boolean indicating if execution should continue or not.</returns>
 48    public bool OnDirectoryFailure(string directory, Exception e)
 49    {
 50      bool result = false;
 51      DirectoryFailureHandler handler = DirectoryFailure;
 52
 53      if (handler != null) {
 54        var args = new ScanFailureEventArgs(directory, e);
 55        handler(this, args);
 56        result = args.ContinueRunning;
 57      }
 58      return result;
 59    }
 60
 61    /// <summary>
 62    /// Fires the <see cref="FileFailure"> file failure handler delegate</see>.
 63    /// </summary>
 64    /// <param name="file">The file causing the failure.</param>
 65    /// <param name="e">The exception for this failure.</param>
 66    /// <returns>A boolean indicating if execution should continue or not.</returns>
 67    public bool OnFileFailure(string file, Exception e)
 68    {
 69      FileFailureHandler handler = FileFailure;
 70      bool result = (handler != null);
 71
 72      if (result) {
 73        var args = new ScanFailureEventArgs(file, e);
 74        handler(this, args);
 75        result = args.ContinueRunning;
 76      }
 77      return result;
 78    }
 79
 80    /// <summary>
 81    /// Fires the <see cref="ProcessFile">ProcessFile delegate</see>.
 82    /// </summary>
 83    /// <param name="file">The file being processed.</param>
 84    /// <returns>A boolean indicating if execution should continue or not.</returns>
 85    public bool OnProcessFile(string file)
 86    {
 87      bool result = true;
 88      ProcessFileHandler handler = ProcessFile;
 89
 90      if (handler != null) {
 91        var args = new ScanEventArgs(file);
 92        handler(this, args);
 93        result = args.ContinueRunning;
 94      }
 95      return result;
 96    }
 97
 98    /// <summary>
 99    /// Fires the <see cref="CompletedFile"/> delegate
 100    /// </summary>
 101    /// <param name="file">The file whose processing has been completed.</param>
 102    /// <returns>A boolean indicating if execution should continue or not.</returns>
 103    public bool OnCompletedFile(string file)
 104    {
 105      bool result = true;
 106      CompletedFileHandler handler = CompletedFile;
 107      if (handler != null) {
 108        var args = new ScanEventArgs(file);
 109        handler(this, args);
 110        result = args.ContinueRunning;
 111      }
 112      return result;
 113    }
 114
 115    /// <summary>
 116    /// Fires the <see cref="ProcessDirectory">process directory</see> delegate.
 117    /// </summary>
 118    /// <param name="directory">The directory being processed.</param>
 119    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files as determined by the current 
 120    /// <returns>A <see cref="bool"/> of true if the operation should continue; false otherwise.</returns>
 121    public bool OnProcessDirectory(string directory, bool hasMatchingFiles)
 122    {
 123      bool result = true;
 124      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;
 125      if (handler != null) {
 126        var args = new DirectoryEventArgs(directory, hasMatchingFiles);
 127        handler(this, args);
 128        result = args.ContinueRunning;
 129      }
 130      return result;
 131    }
 132
 133    /// <summary>
 134    /// The minimum timespan between <see cref="Progress"/> events.
 135    /// </summary>
 136    /// <value>The minimum period of time between <see cref="Progress"/> events.</value>
 137    /// <seealso cref="Progress"/>
 138    /// <remarks>The default interval is three seconds.</remarks>
 139    public TimeSpan ProgressInterval {
 140      get { return progressInterval_; }
 141      set { progressInterval_ = value; }
 142    }
 143
 144    #region Instance Fields
 145    TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);
 146    #endregion
 147  }
 148
 149  /// <summary>
 150  /// FastZip provides facilities for creating and extracting zip files.
 151  /// </summary>
 152  public class FastZip
 153  {
 154    #region Enumerations
 155    /// <summary>
 156    /// Defines the desired handling when overwriting files during extraction.
 157    /// </summary>
 158    public enum Overwrite
 159    {
 160      /// <summary>
 161      /// Prompt the user to confirm overwriting
 162      /// </summary>
 163      Prompt,
 164      /// <summary>
 165      /// Never overwrite files.
 166      /// </summary>
 167      Never,
 168      /// <summary>
 169      /// Always overwrite files.
 170      /// </summary>
 171      Always
 172    }
 173    #endregion
 174
 175    #region Constructors
 176    /// <summary>
 177    /// Initialise a default instance of <see cref="FastZip"/>.
 178    /// </summary>
 5179    public FastZip()
 180    {
 5181    }
 182
 183    /// <summary>
 184    /// Initialise a new instance of <see cref="FastZip"/>
 185    /// </summary>
 186    /// <param name="events">The <see cref="FastZipEvents">events</see> to use during operations.</param>
 0187    public FastZip(FastZipEvents events)
 188    {
 0189      events_ = events;
 0190    }
 191    #endregion
 192
 193    #region Properties
 194    /// <summary>
 195    /// Get/set a value indicating wether empty directories should be created.
 196    /// </summary>
 197    public bool CreateEmptyDirectories {
 6198      get { return createEmptyDirectories_; }
 2199      set { createEmptyDirectories_ = value; }
 200    }
 201
 202    /// <summary>
 203    /// Get / set the password value.
 204    /// </summary>
 205    public string Password {
 0206      get { return password_; }
 4207      set { password_ = value; }
 208    }
 209
 210    /// <summary>
 211    /// Get or set the <see cref="INameTransform"></see> active when creating Zip files.
 212    /// </summary>
 213    /// <seealso cref="EntryFactory"></seealso>
 214    public INameTransform NameTransform {
 0215      get { return entryFactory_.NameTransform; }
 216      set {
 4217        entryFactory_.NameTransform = value;
 4218      }
 219    }
 220
 221    /// <summary>
 222    /// Get or set the <see cref="IEntryFactory"></see> active when creating Zip files.
 223    /// </summary>
 224    public IEntryFactory EntryFactory {
 0225      get { return entryFactory_; }
 226      set {
 1227         if (value == null) {
 0228          entryFactory_ = new ZipEntryFactory();
 0229        } else {
 1230          entryFactory_ = value;
 231        }
 1232      }
 233    }
 234
 235    /// <summary>
 236    /// Gets or sets the setting for <see cref="UseZip64">Zip64 handling when writing.</see>
 237    /// </summary>
 238    /// <remarks>
 239    /// The default value is dynamic which is not backwards compatible with old
 240    /// programs and can cause problems with XP's built in compression which cant
 241    /// read Zip64 archives. However it does avoid the situation were a large file
 242    /// is added and cannot be completed correctly.
 243    /// NOTE: Setting the size for entries before they are added is the best solution!
 244    /// By default the EntryFactory used by FastZip will set fhe file size.
 245    /// </remarks>
 246    public UseZip64 UseZip64 {
 4247      get { return useZip64_; }
 0248      set { useZip64_ = value; }
 249    }
 250
 251    /// <summary>
 252    /// Get/set a value indicating wether file dates and times should
 253    /// be restored when extracting files from an archive.
 254    /// </summary>
 255    /// <remarks>The default value is false.</remarks>
 256    public bool RestoreDateTimeOnExtract {
 257      get {
 0258        return restoreDateTimeOnExtract_;
 259      }
 260      set {
 0261        restoreDateTimeOnExtract_ = value;
 0262      }
 263    }
 264
 265    /// <summary>
 266    /// Get/set a value indicating wether file attributes should
 267    /// be restored during extract operations
 268    /// </summary>
 269    public bool RestoreAttributesOnExtract {
 0270      get { return restoreAttributesOnExtract_; }
 0271      set { restoreAttributesOnExtract_ = value; }
 272    }
 273    #endregion
 274
 275    #region Delegates
 276    /// <summary>
 277    /// Delegate called when confirming overwriting of files.
 278    /// </summary>
 279    public delegate bool ConfirmOverwriteDelegate(string fileName);
 280    #endregion
 281
 282    #region CreateZip
 283    /// <summary>
 284    /// Create a zip file.
 285    /// </summary>
 286    /// <param name="zipFileName">The name of the zip file to create.</param>
 287    /// <param name="sourceDirectory">The directory to source files from.</param>
 288    /// <param name="recurse">True to recurse directories, false for no recursion.</param>
 289    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
 290    /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
 291    public void CreateZip(string zipFileName, string sourceDirectory,
 292      bool recurse, string fileFilter, string directoryFilter)
 293    {
 0294      CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, directoryFilter);
 0295    }
 296
 297    /// <summary>
 298    /// Create a zip file/archive.
 299    /// </summary>
 300    /// <param name="zipFileName">The name of the zip file to create.</param>
 301    /// <param name="sourceDirectory">The directory to obtain files and directories from.</param>
 302    /// <param name="recurse">True to recurse directories, false for no recursion.</param>
 303    /// <param name="fileFilter">The file filter to apply.</param>
 304    public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)
 305    {
 0306      CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, null);
 0307    }
 308
 309    /// <summary>
 310    /// Create a zip archive sending output to the <paramref name="outputStream"/> passed.
 311    /// </summary>
 312    /// <param name="outputStream">The stream to write archive data to.</param>
 313    /// <param name="sourceDirectory">The directory to source files from.</param>
 314    /// <param name="recurse">True to recurse directories, false for no recursion.</param>
 315    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
 316    /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
 317    /// <remarks>The <paramref name="outputStream"/> is closed after creation.</remarks>
 318    public void CreateZip(Stream outputStream, string sourceDirectory, bool recurse, string fileFilter, string directory
 319    {
 4320      NameTransform = new ZipNameTransform(sourceDirectory);
 4321      sourceDirectory_ = sourceDirectory;
 322
 4323      using (outputStream_ = new ZipOutputStream(outputStream)) {
 324
 4325         if (password_ != null) {
 2326          outputStream_.Password = password_;
 327        }
 328
 4329        outputStream_.UseZip64 = UseZip64;
 4330        var scanner = new FileSystemScanner(fileFilter, directoryFilter);
 4331        scanner.ProcessFile += ProcessFile;
 4332         if (this.CreateEmptyDirectories) {
 0333          scanner.ProcessDirectory += ProcessDirectory;
 334        }
 335
 4336         if (events_ != null) {
 0337           if (events_.FileFailure != null) {
 0338            scanner.FileFailure += events_.FileFailure;
 339          }
 340
 0341           if (events_.DirectoryFailure != null) {
 0342            scanner.DirectoryFailure += events_.DirectoryFailure;
 343          }
 344        }
 345
 4346        scanner.Scan(sourceDirectory, recurse);
 4347      }
 4348    }
 349
 350    #endregion
 351
 352    #region ExtractZip
 353    /// <summary>
 354    /// Extract the contents of a zip file.
 355    /// </summary>
 356    /// <param name="zipFileName">The zip file to extract from.</param>
 357    /// <param name="targetDirectory">The directory to save extracted information in.</param>
 358    /// <param name="fileFilter">A filter to apply to files.</param>
 359    public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter)
 360    {
 1361      ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null, restoreDateTimeOnExtract_);
 1362    }
 363
 364    /// <summary>
 365    /// Extract the contents of a zip file.
 366    /// </summary>
 367    /// <param name="zipFileName">The zip file to extract from.</param>
 368    /// <param name="targetDirectory">The directory to save extracted information in.</param>
 369    /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
 370    /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
 371    /// <param name="fileFilter">A filter to apply to files.</param>
 372    /// <param name="directoryFilter">A filter to apply to directories.</param>
 373    /// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>
 374    public void ExtractZip(string zipFileName, string targetDirectory,
 375                 Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
 376                 string fileFilter, string directoryFilter, bool restoreDateTime)
 377    {
 1378      Stream inputStream = File.Open(zipFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
 1379      ExtractZip(inputStream, targetDirectory, overwrite, confirmDelegate, fileFilter, directoryFilter, restoreDateTime,
 1380    }
 381
 382    /// <summary>
 383    /// Extract the contents of a zip file held in a stream.
 384    /// </summary>
 385    /// <param name="inputStream">The seekable input stream containing the zip to extract from.</param>
 386    /// <param name="targetDirectory">The directory to save extracted information in.</param>
 387    /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
 388    /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
 389    /// <param name="fileFilter">A filter to apply to files.</param>
 390    /// <param name="directoryFilter">A filter to apply to directories.</param>
 391    /// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>
 392    /// <param name="isStreamOwner">Flag indicating whether the inputStream will be closed by this method.</param>
 393    public void ExtractZip(Stream inputStream, string targetDirectory,
 394             Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
 395             string fileFilter, string directoryFilter, bool restoreDateTime,
 396             bool isStreamOwner)
 397    {
 1398       if ((overwrite == Overwrite.Prompt) && (confirmDelegate == null)) {
 0399        throw new ArgumentNullException(nameof(confirmDelegate));
 400      }
 401
 1402      continueRunning_ = true;
 1403      overwrite_ = overwrite;
 1404      confirmDelegate_ = confirmDelegate;
 1405      extractNameTransform_ = new WindowsNameTransform(targetDirectory);
 406
 1407      fileFilter_ = new NameFilter(fileFilter);
 1408      directoryFilter_ = new NameFilter(directoryFilter);
 1409      restoreDateTimeOnExtract_ = restoreDateTime;
 410
 1411      using (zipFile_ = new ZipFile(inputStream)) {
 412
 1413         if (password_ != null) {
 0414          zipFile_.Password = password_;
 415        }
 1416        zipFile_.IsStreamOwner = isStreamOwner;
 1417        System.Collections.IEnumerator enumerator = zipFile_.GetEnumerator();
 2418         while (continueRunning_ && enumerator.MoveNext()) {
 1419          var entry = (ZipEntry)enumerator.Current;
 1420           if (entry.IsFile) {
 421            // TODO Path.GetDirectory can fail here on invalid characters.
 0422             if (directoryFilter_.IsMatch(Path.GetDirectoryName(entry.Name)) && fileFilter_.IsMatch(entry.Name)) {
 0423              ExtractEntry(entry);
 424            }
 1425           } else if (entry.IsDirectory) {
 1426             if (directoryFilter_.IsMatch(entry.Name) && CreateEmptyDirectories) {
 1427              ExtractEntry(entry);
 428            }
 429          } else {
 430            // Do nothing for volume labels etc...
 431          }
 432        }
 1433      }
 1434    }
 435    #endregion
 436
 437    #region Internal Processing
 438    void ProcessDirectory(object sender, DirectoryEventArgs e)
 439    {
 0440       if (!e.HasMatchingFiles && CreateEmptyDirectories) {
 0441         if (events_ != null) {
 0442          events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);
 443        }
 444
 0445         if (e.ContinueRunning) {
 0446           if (e.Name != sourceDirectory_) {
 0447            ZipEntry entry = entryFactory_.MakeDirectoryEntry(e.Name);
 0448            outputStream_.PutNextEntry(entry);
 449          }
 450        }
 451      }
 0452    }
 453
 454    void ProcessFile(object sender, ScanEventArgs e)
 455    {
 4456       if ((events_ != null) && (events_.ProcessFile != null)) {
 0457        events_.ProcessFile(sender, e);
 458      }
 459
 4460       if (e.ContinueRunning) {
 461        try {
 462          // The open below is equivalent to OpenRead which gaurantees that if opened the
 463          // file will not be changed by subsequent openers, but precludes opening in some cases
 464          // were it could succeed. ie the open may fail as its already open for writing and the share mode should refle
 4465          using (FileStream stream = File.Open(e.Name, FileMode.Open, FileAccess.Read, FileShare.Read)) {
 4466            ZipEntry entry = entryFactory_.MakeFileEntry(e.Name);
 4467            outputStream_.PutNextEntry(entry);
 4468            AddFileContents(e.Name, stream);
 4469          }
 4470        } catch (Exception ex) {
 0471           if (events_ != null) {
 0472            continueRunning_ = events_.OnFileFailure(e.Name, ex);
 0473          } else {
 0474            continueRunning_ = false;
 0475            throw;
 476          }
 0477        }
 478      }
 4479    }
 480
 481    void AddFileContents(string name, Stream stream)
 482    {
 4483       if (stream == null) {
 0484        throw new ArgumentNullException(nameof(stream));
 485      }
 486
 4487       if (buffer_ == null) {
 4488        buffer_ = new byte[4096];
 489      }
 490
 4491       if ((events_ != null) && (events_.Progress != null)) {
 0492        StreamUtils.Copy(stream, outputStream_, buffer_,
 0493          events_.Progress, events_.ProgressInterval, this, name);
 0494      } else {
 4495        StreamUtils.Copy(stream, outputStream_, buffer_);
 496      }
 497
 4498       if (events_ != null) {
 0499        continueRunning_ = events_.OnCompletedFile(name);
 500      }
 4501    }
 502
 503    void ExtractFileEntry(ZipEntry entry, string targetName)
 504    {
 0505      bool proceed = true;
 0506       if (overwrite_ != Overwrite.Always) {
 0507         if (File.Exists(targetName)) {
 0508           if ((overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null)) {
 0509            proceed = confirmDelegate_(targetName);
 0510          } else {
 0511            proceed = false;
 512          }
 513        }
 514      }
 515
 0516       if (proceed) {
 0517         if (events_ != null) {
 0518          continueRunning_ = events_.OnProcessFile(entry.Name);
 519        }
 520
 0521         if (continueRunning_) {
 522          try {
 0523            using (FileStream outputStream = File.Create(targetName)) {
 0524               if (buffer_ == null) {
 0525                buffer_ = new byte[4096];
 526              }
 0527               if ((events_ != null) && (events_.Progress != null)) {
 0528                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_,
 0529                  events_.Progress, events_.ProgressInterval, this, entry.Name, entry.Size);
 0530              } else {
 0531                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_);
 532              }
 533
 0534               if (events_ != null) {
 0535                continueRunning_ = events_.OnCompletedFile(entry.Name);
 536              }
 0537            }
 538
 0539             if (restoreDateTimeOnExtract_) {
 0540              File.SetLastWriteTime(targetName, entry.DateTime);
 541            }
 542
 0543             if (RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1)) {
 0544              var fileAttributes = (FileAttributes)entry.ExternalFileAttributes;
 545              // TODO: FastZip - Setting of other file attributes on extraction is a little trickier.
 0546              fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttribut
 0547              File.SetAttributes(targetName, fileAttributes);
 548            }
 0549          } catch (Exception ex) {
 0550             if (events_ != null) {
 0551              continueRunning_ = events_.OnFileFailure(targetName, ex);
 0552            } else {
 0553              continueRunning_ = false;
 0554              throw;
 555            }
 0556          }
 557        }
 558      }
 0559    }
 560
 561    void ExtractEntry(ZipEntry entry)
 562    {
 1563      bool doExtraction = entry.IsCompressionMethodSupported();
 1564      string targetName = entry.Name;
 565
 1566       if (doExtraction) {
 1567         if (entry.IsFile) {
 0568          targetName = extractNameTransform_.TransformFile(targetName);
 1569         } else if (entry.IsDirectory) {
 1570          targetName = extractNameTransform_.TransformDirectory(targetName);
 571        }
 572
 1573        doExtraction = !(string.IsNullOrEmpty(targetName));
 574      }
 575
 576      // TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?
 577
 1578      string dirName = null;
 579
 1580       if (doExtraction) {
 1581         if (entry.IsDirectory) {
 1582          dirName = targetName;
 1583        } else {
 0584          dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));
 585        }
 586      }
 587
 1588       if (doExtraction && !Directory.Exists(dirName)) {
 1589         if (!entry.IsDirectory || CreateEmptyDirectories) {
 590          try {
 1591            Directory.CreateDirectory(dirName);
 1592          } catch (Exception ex) {
 0593            doExtraction = false;
 0594             if (events_ != null) {
 0595               if (entry.IsDirectory) {
 0596                continueRunning_ = events_.OnDirectoryFailure(targetName, ex);
 0597              } else {
 0598                continueRunning_ = events_.OnFileFailure(targetName, ex);
 599              }
 0600            } else {
 0601              continueRunning_ = false;
 0602              throw;
 603            }
 0604          }
 605        }
 606      }
 607
 1608       if (doExtraction && entry.IsFile) {
 0609        ExtractFileEntry(entry, targetName);
 610      }
 1611    }
 612
 613    static int MakeExternalAttributes(FileInfo info)
 614    {
 0615      return (int)info.Attributes;
 616    }
 617
 618    static bool NameIsValid(string name)
 619    {
 0620      return !string.IsNullOrEmpty(name) &&
 0621        (name.IndexOfAny(Path.GetInvalidPathChars()) < 0);
 622    }
 623    #endregion
 624
 625    #region Instance Fields
 626    bool continueRunning_;
 627    byte[] buffer_;
 628    ZipOutputStream outputStream_;
 629    ZipFile zipFile_;
 630    string sourceDirectory_;
 631    NameFilter fileFilter_;
 632    NameFilter directoryFilter_;
 633    Overwrite overwrite_;
 634    ConfirmOverwriteDelegate confirmDelegate_;
 635
 636    bool restoreDateTimeOnExtract_;
 637    bool restoreAttributesOnExtract_;
 638    bool createEmptyDirectories_;
 639    FastZipEvents events_;
 5640    IEntryFactory entryFactory_ = new ZipEntryFactory();
 641    INameTransform extractNameTransform_;
 5642    UseZip64 useZip64_ = UseZip64.Dynamic;
 643
 644    string password_;
 645
 646    #endregion
 647  }
 648}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_FastZipEvents.htm b/docs/opencover/ICSharpCode.SharpZipLib_FastZipEvents.htm new file mode 100644 index 000000000..98f6d3671 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_FastZipEvents.htm @@ -0,0 +1,695 @@ + + + + +ICSharpCode.SharpZipLib.Zip.FastZipEvents - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.FastZipEvents
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\FastZip.cs
Covered lines:0
Uncovered lines:38
Coverable lines:38
Total lines:648
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
OnDirectoryFailure(...)200
OnFileFailure(...)200
OnProcessFile(...)200
OnCompletedFile(...)200
OnProcessDirectory(...)200
.ctor()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\FastZip.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using ICSharpCode.SharpZipLib.Core;
 4
 5namespace ICSharpCode.SharpZipLib.Zip
 6{
 7  /// <summary>
 8  /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.
 9  /// </summary>
 10  public class FastZipEvents
 11  {
 12    /// <summary>
 13    /// Delegate to invoke when processing directories.
 14    /// </summary>
 15    public event EventHandler<DirectoryEventArgs> ProcessDirectory;
 16
 17    /// <summary>
 18    /// Delegate to invoke when processing files.
 19    /// </summary>
 20    public ProcessFileHandler ProcessFile;
 21
 22    /// <summary>
 23    /// Delegate to invoke during processing of files.
 24    /// </summary>
 25    public ProgressHandler Progress;
 26
 27    /// <summary>
 28    /// Delegate to invoke when processing for a file has been completed.
 29    /// </summary>
 30    public CompletedFileHandler CompletedFile;
 31
 32    /// <summary>
 33    /// Delegate to invoke when processing directory failures.
 34    /// </summary>
 35    public DirectoryFailureHandler DirectoryFailure;
 36
 37    /// <summary>
 38    /// Delegate to invoke when processing file failures.
 39    /// </summary>
 40    public FileFailureHandler FileFailure;
 41
 42    /// <summary>
 43    /// Raise the <see cref="DirectoryFailure">directory failure</see> event.
 44    /// </summary>
 45    /// <param name="directory">The directory causing the failure.</param>
 46    /// <param name="e">The exception for this event.</param>
 47    /// <returns>A boolean indicating if execution should continue or not.</returns>
 48    public bool OnDirectoryFailure(string directory, Exception e)
 49    {
 050      bool result = false;
 051      DirectoryFailureHandler handler = DirectoryFailure;
 52
 053       if (handler != null) {
 054        var args = new ScanFailureEventArgs(directory, e);
 055        handler(this, args);
 056        result = args.ContinueRunning;
 57      }
 058      return result;
 59    }
 60
 61    /// <summary>
 62    /// Fires the <see cref="FileFailure"> file failure handler delegate</see>.
 63    /// </summary>
 64    /// <param name="file">The file causing the failure.</param>
 65    /// <param name="e">The exception for this failure.</param>
 66    /// <returns>A boolean indicating if execution should continue or not.</returns>
 67    public bool OnFileFailure(string file, Exception e)
 68    {
 069      FileFailureHandler handler = FileFailure;
 070      bool result = (handler != null);
 71
 072       if (result) {
 073        var args = new ScanFailureEventArgs(file, e);
 074        handler(this, args);
 075        result = args.ContinueRunning;
 76      }
 077      return result;
 78    }
 79
 80    /// <summary>
 81    /// Fires the <see cref="ProcessFile">ProcessFile delegate</see>.
 82    /// </summary>
 83    /// <param name="file">The file being processed.</param>
 84    /// <returns>A boolean indicating if execution should continue or not.</returns>
 85    public bool OnProcessFile(string file)
 86    {
 087      bool result = true;
 088      ProcessFileHandler handler = ProcessFile;
 89
 090       if (handler != null) {
 091        var args = new ScanEventArgs(file);
 092        handler(this, args);
 093        result = args.ContinueRunning;
 94      }
 095      return result;
 96    }
 97
 98    /// <summary>
 99    /// Fires the <see cref="CompletedFile"/> delegate
 100    /// </summary>
 101    /// <param name="file">The file whose processing has been completed.</param>
 102    /// <returns>A boolean indicating if execution should continue or not.</returns>
 103    public bool OnCompletedFile(string file)
 104    {
 0105      bool result = true;
 0106      CompletedFileHandler handler = CompletedFile;
 0107       if (handler != null) {
 0108        var args = new ScanEventArgs(file);
 0109        handler(this, args);
 0110        result = args.ContinueRunning;
 111      }
 0112      return result;
 113    }
 114
 115    /// <summary>
 116    /// Fires the <see cref="ProcessDirectory">process directory</see> delegate.
 117    /// </summary>
 118    /// <param name="directory">The directory being processed.</param>
 119    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files as determined by the current 
 120    /// <returns>A <see cref="bool"/> of true if the operation should continue; false otherwise.</returns>
 121    public bool OnProcessDirectory(string directory, bool hasMatchingFiles)
 122    {
 0123      bool result = true;
 0124      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;
 0125       if (handler != null) {
 0126        var args = new DirectoryEventArgs(directory, hasMatchingFiles);
 0127        handler(this, args);
 0128        result = args.ContinueRunning;
 129      }
 0130      return result;
 131    }
 132
 133    /// <summary>
 134    /// The minimum timespan between <see cref="Progress"/> events.
 135    /// </summary>
 136    /// <value>The minimum period of time between <see cref="Progress"/> events.</value>
 137    /// <seealso cref="Progress"/>
 138    /// <remarks>The default interval is three seconds.</remarks>
 139    public TimeSpan ProgressInterval {
 0140      get { return progressInterval_; }
 0141      set { progressInterval_ = value; }
 142    }
 143
 144    #region Instance Fields
 0145    TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);
 146    #endregion
 147  }
 148
 149  /// <summary>
 150  /// FastZip provides facilities for creating and extracting zip files.
 151  /// </summary>
 152  public class FastZip
 153  {
 154    #region Enumerations
 155    /// <summary>
 156    /// Defines the desired handling when overwriting files during extraction.
 157    /// </summary>
 158    public enum Overwrite
 159    {
 160      /// <summary>
 161      /// Prompt the user to confirm overwriting
 162      /// </summary>
 163      Prompt,
 164      /// <summary>
 165      /// Never overwrite files.
 166      /// </summary>
 167      Never,
 168      /// <summary>
 169      /// Always overwrite files.
 170      /// </summary>
 171      Always
 172    }
 173    #endregion
 174
 175    #region Constructors
 176    /// <summary>
 177    /// Initialise a default instance of <see cref="FastZip"/>.
 178    /// </summary>
 179    public FastZip()
 180    {
 181    }
 182
 183    /// <summary>
 184    /// Initialise a new instance of <see cref="FastZip"/>
 185    /// </summary>
 186    /// <param name="events">The <see cref="FastZipEvents">events</see> to use during operations.</param>
 187    public FastZip(FastZipEvents events)
 188    {
 189      events_ = events;
 190    }
 191    #endregion
 192
 193    #region Properties
 194    /// <summary>
 195    /// Get/set a value indicating wether empty directories should be created.
 196    /// </summary>
 197    public bool CreateEmptyDirectories {
 198      get { return createEmptyDirectories_; }
 199      set { createEmptyDirectories_ = value; }
 200    }
 201
 202    /// <summary>
 203    /// Get / set the password value.
 204    /// </summary>
 205    public string Password {
 206      get { return password_; }
 207      set { password_ = value; }
 208    }
 209
 210    /// <summary>
 211    /// Get or set the <see cref="INameTransform"></see> active when creating Zip files.
 212    /// </summary>
 213    /// <seealso cref="EntryFactory"></seealso>
 214    public INameTransform NameTransform {
 215      get { return entryFactory_.NameTransform; }
 216      set {
 217        entryFactory_.NameTransform = value;
 218      }
 219    }
 220
 221    /// <summary>
 222    /// Get or set the <see cref="IEntryFactory"></see> active when creating Zip files.
 223    /// </summary>
 224    public IEntryFactory EntryFactory {
 225      get { return entryFactory_; }
 226      set {
 227        if (value == null) {
 228          entryFactory_ = new ZipEntryFactory();
 229        } else {
 230          entryFactory_ = value;
 231        }
 232      }
 233    }
 234
 235    /// <summary>
 236    /// Gets or sets the setting for <see cref="UseZip64">Zip64 handling when writing.</see>
 237    /// </summary>
 238    /// <remarks>
 239    /// The default value is dynamic which is not backwards compatible with old
 240    /// programs and can cause problems with XP's built in compression which cant
 241    /// read Zip64 archives. However it does avoid the situation were a large file
 242    /// is added and cannot be completed correctly.
 243    /// NOTE: Setting the size for entries before they are added is the best solution!
 244    /// By default the EntryFactory used by FastZip will set fhe file size.
 245    /// </remarks>
 246    public UseZip64 UseZip64 {
 247      get { return useZip64_; }
 248      set { useZip64_ = value; }
 249    }
 250
 251    /// <summary>
 252    /// Get/set a value indicating wether file dates and times should
 253    /// be restored when extracting files from an archive.
 254    /// </summary>
 255    /// <remarks>The default value is false.</remarks>
 256    public bool RestoreDateTimeOnExtract {
 257      get {
 258        return restoreDateTimeOnExtract_;
 259      }
 260      set {
 261        restoreDateTimeOnExtract_ = value;
 262      }
 263    }
 264
 265    /// <summary>
 266    /// Get/set a value indicating wether file attributes should
 267    /// be restored during extract operations
 268    /// </summary>
 269    public bool RestoreAttributesOnExtract {
 270      get { return restoreAttributesOnExtract_; }
 271      set { restoreAttributesOnExtract_ = value; }
 272    }
 273    #endregion
 274
 275    #region Delegates
 276    /// <summary>
 277    /// Delegate called when confirming overwriting of files.
 278    /// </summary>
 279    public delegate bool ConfirmOverwriteDelegate(string fileName);
 280    #endregion
 281
 282    #region CreateZip
 283    /// <summary>
 284    /// Create a zip file.
 285    /// </summary>
 286    /// <param name="zipFileName">The name of the zip file to create.</param>
 287    /// <param name="sourceDirectory">The directory to source files from.</param>
 288    /// <param name="recurse">True to recurse directories, false for no recursion.</param>
 289    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
 290    /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
 291    public void CreateZip(string zipFileName, string sourceDirectory,
 292      bool recurse, string fileFilter, string directoryFilter)
 293    {
 294      CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, directoryFilter);
 295    }
 296
 297    /// <summary>
 298    /// Create a zip file/archive.
 299    /// </summary>
 300    /// <param name="zipFileName">The name of the zip file to create.</param>
 301    /// <param name="sourceDirectory">The directory to obtain files and directories from.</param>
 302    /// <param name="recurse">True to recurse directories, false for no recursion.</param>
 303    /// <param name="fileFilter">The file filter to apply.</param>
 304    public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)
 305    {
 306      CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, null);
 307    }
 308
 309    /// <summary>
 310    /// Create a zip archive sending output to the <paramref name="outputStream"/> passed.
 311    /// </summary>
 312    /// <param name="outputStream">The stream to write archive data to.</param>
 313    /// <param name="sourceDirectory">The directory to source files from.</param>
 314    /// <param name="recurse">True to recurse directories, false for no recursion.</param>
 315    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
 316    /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
 317    /// <remarks>The <paramref name="outputStream"/> is closed after creation.</remarks>
 318    public void CreateZip(Stream outputStream, string sourceDirectory, bool recurse, string fileFilter, string directory
 319    {
 320      NameTransform = new ZipNameTransform(sourceDirectory);
 321      sourceDirectory_ = sourceDirectory;
 322
 323      using (outputStream_ = new ZipOutputStream(outputStream)) {
 324
 325        if (password_ != null) {
 326          outputStream_.Password = password_;
 327        }
 328
 329        outputStream_.UseZip64 = UseZip64;
 330        var scanner = new FileSystemScanner(fileFilter, directoryFilter);
 331        scanner.ProcessFile += ProcessFile;
 332        if (this.CreateEmptyDirectories) {
 333          scanner.ProcessDirectory += ProcessDirectory;
 334        }
 335
 336        if (events_ != null) {
 337          if (events_.FileFailure != null) {
 338            scanner.FileFailure += events_.FileFailure;
 339          }
 340
 341          if (events_.DirectoryFailure != null) {
 342            scanner.DirectoryFailure += events_.DirectoryFailure;
 343          }
 344        }
 345
 346        scanner.Scan(sourceDirectory, recurse);
 347      }
 348    }
 349
 350    #endregion
 351
 352    #region ExtractZip
 353    /// <summary>
 354    /// Extract the contents of a zip file.
 355    /// </summary>
 356    /// <param name="zipFileName">The zip file to extract from.</param>
 357    /// <param name="targetDirectory">The directory to save extracted information in.</param>
 358    /// <param name="fileFilter">A filter to apply to files.</param>
 359    public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter)
 360    {
 361      ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null, restoreDateTimeOnExtract_);
 362    }
 363
 364    /// <summary>
 365    /// Extract the contents of a zip file.
 366    /// </summary>
 367    /// <param name="zipFileName">The zip file to extract from.</param>
 368    /// <param name="targetDirectory">The directory to save extracted information in.</param>
 369    /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
 370    /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
 371    /// <param name="fileFilter">A filter to apply to files.</param>
 372    /// <param name="directoryFilter">A filter to apply to directories.</param>
 373    /// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>
 374    public void ExtractZip(string zipFileName, string targetDirectory,
 375                 Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
 376                 string fileFilter, string directoryFilter, bool restoreDateTime)
 377    {
 378      Stream inputStream = File.Open(zipFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
 379      ExtractZip(inputStream, targetDirectory, overwrite, confirmDelegate, fileFilter, directoryFilter, restoreDateTime,
 380    }
 381
 382    /// <summary>
 383    /// Extract the contents of a zip file held in a stream.
 384    /// </summary>
 385    /// <param name="inputStream">The seekable input stream containing the zip to extract from.</param>
 386    /// <param name="targetDirectory">The directory to save extracted information in.</param>
 387    /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
 388    /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
 389    /// <param name="fileFilter">A filter to apply to files.</param>
 390    /// <param name="directoryFilter">A filter to apply to directories.</param>
 391    /// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>
 392    /// <param name="isStreamOwner">Flag indicating whether the inputStream will be closed by this method.</param>
 393    public void ExtractZip(Stream inputStream, string targetDirectory,
 394             Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
 395             string fileFilter, string directoryFilter, bool restoreDateTime,
 396             bool isStreamOwner)
 397    {
 398      if ((overwrite == Overwrite.Prompt) && (confirmDelegate == null)) {
 399        throw new ArgumentNullException(nameof(confirmDelegate));
 400      }
 401
 402      continueRunning_ = true;
 403      overwrite_ = overwrite;
 404      confirmDelegate_ = confirmDelegate;
 405      extractNameTransform_ = new WindowsNameTransform(targetDirectory);
 406
 407      fileFilter_ = new NameFilter(fileFilter);
 408      directoryFilter_ = new NameFilter(directoryFilter);
 409      restoreDateTimeOnExtract_ = restoreDateTime;
 410
 411      using (zipFile_ = new ZipFile(inputStream)) {
 412
 413        if (password_ != null) {
 414          zipFile_.Password = password_;
 415        }
 416        zipFile_.IsStreamOwner = isStreamOwner;
 417        System.Collections.IEnumerator enumerator = zipFile_.GetEnumerator();
 418        while (continueRunning_ && enumerator.MoveNext()) {
 419          var entry = (ZipEntry)enumerator.Current;
 420          if (entry.IsFile) {
 421            // TODO Path.GetDirectory can fail here on invalid characters.
 422            if (directoryFilter_.IsMatch(Path.GetDirectoryName(entry.Name)) && fileFilter_.IsMatch(entry.Name)) {
 423              ExtractEntry(entry);
 424            }
 425          } else if (entry.IsDirectory) {
 426            if (directoryFilter_.IsMatch(entry.Name) && CreateEmptyDirectories) {
 427              ExtractEntry(entry);
 428            }
 429          } else {
 430            // Do nothing for volume labels etc...
 431          }
 432        }
 433      }
 434    }
 435    #endregion
 436
 437    #region Internal Processing
 438    void ProcessDirectory(object sender, DirectoryEventArgs e)
 439    {
 440      if (!e.HasMatchingFiles && CreateEmptyDirectories) {
 441        if (events_ != null) {
 442          events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);
 443        }
 444
 445        if (e.ContinueRunning) {
 446          if (e.Name != sourceDirectory_) {
 447            ZipEntry entry = entryFactory_.MakeDirectoryEntry(e.Name);
 448            outputStream_.PutNextEntry(entry);
 449          }
 450        }
 451      }
 452    }
 453
 454    void ProcessFile(object sender, ScanEventArgs e)
 455    {
 456      if ((events_ != null) && (events_.ProcessFile != null)) {
 457        events_.ProcessFile(sender, e);
 458      }
 459
 460      if (e.ContinueRunning) {
 461        try {
 462          // The open below is equivalent to OpenRead which gaurantees that if opened the
 463          // file will not be changed by subsequent openers, but precludes opening in some cases
 464          // were it could succeed. ie the open may fail as its already open for writing and the share mode should refle
 465          using (FileStream stream = File.Open(e.Name, FileMode.Open, FileAccess.Read, FileShare.Read)) {
 466            ZipEntry entry = entryFactory_.MakeFileEntry(e.Name);
 467            outputStream_.PutNextEntry(entry);
 468            AddFileContents(e.Name, stream);
 469          }
 470        } catch (Exception ex) {
 471          if (events_ != null) {
 472            continueRunning_ = events_.OnFileFailure(e.Name, ex);
 473          } else {
 474            continueRunning_ = false;
 475            throw;
 476          }
 477        }
 478      }
 479    }
 480
 481    void AddFileContents(string name, Stream stream)
 482    {
 483      if (stream == null) {
 484        throw new ArgumentNullException(nameof(stream));
 485      }
 486
 487      if (buffer_ == null) {
 488        buffer_ = new byte[4096];
 489      }
 490
 491      if ((events_ != null) && (events_.Progress != null)) {
 492        StreamUtils.Copy(stream, outputStream_, buffer_,
 493          events_.Progress, events_.ProgressInterval, this, name);
 494      } else {
 495        StreamUtils.Copy(stream, outputStream_, buffer_);
 496      }
 497
 498      if (events_ != null) {
 499        continueRunning_ = events_.OnCompletedFile(name);
 500      }
 501    }
 502
 503    void ExtractFileEntry(ZipEntry entry, string targetName)
 504    {
 505      bool proceed = true;
 506      if (overwrite_ != Overwrite.Always) {
 507        if (File.Exists(targetName)) {
 508          if ((overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null)) {
 509            proceed = confirmDelegate_(targetName);
 510          } else {
 511            proceed = false;
 512          }
 513        }
 514      }
 515
 516      if (proceed) {
 517        if (events_ != null) {
 518          continueRunning_ = events_.OnProcessFile(entry.Name);
 519        }
 520
 521        if (continueRunning_) {
 522          try {
 523            using (FileStream outputStream = File.Create(targetName)) {
 524              if (buffer_ == null) {
 525                buffer_ = new byte[4096];
 526              }
 527              if ((events_ != null) && (events_.Progress != null)) {
 528                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_,
 529                  events_.Progress, events_.ProgressInterval, this, entry.Name, entry.Size);
 530              } else {
 531                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_);
 532              }
 533
 534              if (events_ != null) {
 535                continueRunning_ = events_.OnCompletedFile(entry.Name);
 536              }
 537            }
 538
 539            if (restoreDateTimeOnExtract_) {
 540              File.SetLastWriteTime(targetName, entry.DateTime);
 541            }
 542
 543            if (RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1)) {
 544              var fileAttributes = (FileAttributes)entry.ExternalFileAttributes;
 545              // TODO: FastZip - Setting of other file attributes on extraction is a little trickier.
 546              fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttribut
 547              File.SetAttributes(targetName, fileAttributes);
 548            }
 549          } catch (Exception ex) {
 550            if (events_ != null) {
 551              continueRunning_ = events_.OnFileFailure(targetName, ex);
 552            } else {
 553              continueRunning_ = false;
 554              throw;
 555            }
 556          }
 557        }
 558      }
 559    }
 560
 561    void ExtractEntry(ZipEntry entry)
 562    {
 563      bool doExtraction = entry.IsCompressionMethodSupported();
 564      string targetName = entry.Name;
 565
 566      if (doExtraction) {
 567        if (entry.IsFile) {
 568          targetName = extractNameTransform_.TransformFile(targetName);
 569        } else if (entry.IsDirectory) {
 570          targetName = extractNameTransform_.TransformDirectory(targetName);
 571        }
 572
 573        doExtraction = !(string.IsNullOrEmpty(targetName));
 574      }
 575
 576      // TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?
 577
 578      string dirName = null;
 579
 580      if (doExtraction) {
 581        if (entry.IsDirectory) {
 582          dirName = targetName;
 583        } else {
 584          dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));
 585        }
 586      }
 587
 588      if (doExtraction && !Directory.Exists(dirName)) {
 589        if (!entry.IsDirectory || CreateEmptyDirectories) {
 590          try {
 591            Directory.CreateDirectory(dirName);
 592          } catch (Exception ex) {
 593            doExtraction = false;
 594            if (events_ != null) {
 595              if (entry.IsDirectory) {
 596                continueRunning_ = events_.OnDirectoryFailure(targetName, ex);
 597              } else {
 598                continueRunning_ = events_.OnFileFailure(targetName, ex);
 599              }
 600            } else {
 601              continueRunning_ = false;
 602              throw;
 603            }
 604          }
 605        }
 606      }
 607
 608      if (doExtraction && entry.IsFile) {
 609        ExtractFileEntry(entry, targetName);
 610      }
 611    }
 612
 613    static int MakeExternalAttributes(FileInfo info)
 614    {
 615      return (int)info.Attributes;
 616    }
 617
 618    static bool NameIsValid(string name)
 619    {
 620      return !string.IsNullOrEmpty(name) &&
 621        (name.IndexOfAny(Path.GetInvalidPathChars()) < 0);
 622    }
 623    #endregion
 624
 625    #region Instance Fields
 626    bool continueRunning_;
 627    byte[] buffer_;
 628    ZipOutputStream outputStream_;
 629    ZipFile zipFile_;
 630    string sourceDirectory_;
 631    NameFilter fileFilter_;
 632    NameFilter directoryFilter_;
 633    Overwrite overwrite_;
 634    ConfirmOverwriteDelegate confirmDelegate_;
 635
 636    bool restoreDateTimeOnExtract_;
 637    bool restoreAttributesOnExtract_;
 638    bool createEmptyDirectories_;
 639    FastZipEvents events_;
 640    IEntryFactory entryFactory_ = new ZipEntryFactory();
 641    INameTransform extractNameTransform_;
 642    UseZip64 useZip64_ = UseZip64.Dynamic;
 643
 644    string password_;
 645
 646    #endregion
 647  }
 648}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_FileFailureHandler.htm b/docs/opencover/ICSharpCode.SharpZipLib_FileFailureHandler.htm new file mode 100644 index 000000000..9585a8faf --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_FileFailureHandler.htm @@ -0,0 +1,29 @@ + + + + +ICSharpCode.SharpZipLib.Core.FileFailureHandler - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.FileFailureHandler
Assembly:ICSharpCode.SharpZipLib
File(s):
Covered lines:0
Uncovered lines:0
Coverable lines:0
Total lines:0
Line coverage:
+

File(s)

+

No files found. This usually happens if a file isn't covered by a test or the class does not contain any sequence points (e.g. a class that only contains auto properties).

+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_FileSystemScanner.htm b/docs/opencover/ICSharpCode.SharpZipLib_FileSystemScanner.htm new file mode 100644 index 000000000..908420467 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_FileSystemScanner.htm @@ -0,0 +1,527 @@ + + + + +ICSharpCode.SharpZipLib.Core.FileSystemScanner - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.FileSystemScanner
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs
Covered lines:33
Uncovered lines:49
Coverable lines:82
Total lines:475
Line coverage:40.2%
Branch coverage:32.3%
+

Metrics

+ + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor(...)1100100
.ctor(...)100
.ctor(...)100
OnDirectoryFailure(...)200
OnFileFailure(...)200
OnProcessFile(...)210066.67
OnCompleteFile(...)200
OnProcessDirectory(...)25066.67
Scan(...)1100100
ScanDir(...)155040
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Core
 4{
 5  #region EventArgs
 6  /// <summary>
 7  /// Event arguments for scanning.
 8  /// </summary>
 9  public class ScanEventArgs : EventArgs
 10  {
 11    #region Constructors
 12    /// <summary>
 13    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 14    /// </summary>
 15    /// <param name="name">The file or directory name.</param>
 16    public ScanEventArgs(string name)
 17    {
 18      name_ = name;
 19    }
 20    #endregion
 21
 22    /// <summary>
 23    /// The file or directory name for this event.
 24    /// </summary>
 25    public string Name {
 26      get { return name_; }
 27    }
 28
 29    /// <summary>
 30    /// Get set a value indicating if scanning should continue or not.
 31    /// </summary>
 32    public bool ContinueRunning {
 33      get { return continueRunning_; }
 34      set { continueRunning_ = value; }
 35    }
 36
 37    #region Instance Fields
 38    string name_;
 39    bool continueRunning_ = true;
 40    #endregion
 41  }
 42
 43  /// <summary>
 44  /// Event arguments during processing of a single file or directory.
 45  /// </summary>
 46  public class ProgressEventArgs : EventArgs
 47  {
 48    #region Constructors
 49    /// <summary>
 50    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 51    /// </summary>
 52    /// <param name="name">The file or directory name if known.</param>
 53    /// <param name="processed">The number of bytes processed so far</param>
 54    /// <param name="target">The total number of bytes to process, 0 if not known</param>
 55    public ProgressEventArgs(string name, long processed, long target)
 56    {
 57      name_ = name;
 58      processed_ = processed;
 59      target_ = target;
 60    }
 61    #endregion
 62
 63    /// <summary>
 64    /// The name for this event if known.
 65    /// </summary>
 66    public string Name {
 67      get { return name_; }
 68    }
 69
 70    /// <summary>
 71    /// Get set a value indicating wether scanning should continue or not.
 72    /// </summary>
 73    public bool ContinueRunning {
 74      get { return continueRunning_; }
 75      set { continueRunning_ = value; }
 76    }
 77
 78    /// <summary>
 79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed
 80    /// </summary>
 81    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>
 82    public float PercentComplete {
 83      get {
 84        float result;
 85        if (target_ <= 0) {
 86          result = 0;
 87        } else {
 88          result = ((float)processed_ / (float)target_) * 100.0f;
 89        }
 90        return result;
 91      }
 92    }
 93
 94    /// <summary>
 95    /// The number of bytes processed so far
 96    /// </summary>
 97    public long Processed {
 98      get { return processed_; }
 99    }
 100
 101    /// <summary>
 102    /// The number of bytes to process.
 103    /// </summary>
 104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>
 105    public long Target {
 106      get { return target_; }
 107    }
 108
 109    #region Instance Fields
 110    string name_;
 111    long processed_;
 112    long target_;
 113    bool continueRunning_ = true;
 114    #endregion
 115  }
 116
 117  /// <summary>
 118  /// Event arguments for directories.
 119  /// </summary>
 120  public class DirectoryEventArgs : ScanEventArgs
 121  {
 122    #region Constructors
 123    /// <summary>
 124    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.
 125    /// </summary>
 126    /// <param name="name">The name for this directory.</param>
 127    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par
 128    public DirectoryEventArgs(string name, bool hasMatchingFiles)
 129      : base(name)
 130    {
 131      hasMatchingFiles_ = hasMatchingFiles;
 132    }
 133    #endregion
 134
 135    /// <summary>
 136    /// Get a value indicating if the directory contains any matching files or not.
 137    /// </summary>
 138    public bool HasMatchingFiles {
 139      get { return hasMatchingFiles_; }
 140    }
 141
 142    readonly
 143
 144    #region Instance Fields
 145    bool hasMatchingFiles_;
 146    #endregion
 147  }
 148
 149  /// <summary>
 150  /// Arguments passed when scan failures are detected.
 151  /// </summary>
 152  public class ScanFailureEventArgs : EventArgs
 153  {
 154    #region Constructors
 155    /// <summary>
 156    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>
 157    /// </summary>
 158    /// <param name="name">The name to apply.</param>
 159    /// <param name="e">The exception to use.</param>
 160    public ScanFailureEventArgs(string name, Exception e)
 161    {
 162      name_ = name;
 163      exception_ = e;
 164      continueRunning_ = true;
 165    }
 166    #endregion
 167
 168    /// <summary>
 169    /// The applicable name.
 170    /// </summary>
 171    public string Name {
 172      get { return name_; }
 173    }
 174
 175    /// <summary>
 176    /// The applicable exception.
 177    /// </summary>
 178    public Exception Exception {
 179      get { return exception_; }
 180    }
 181
 182    /// <summary>
 183    /// Get / set a value indicating wether scanning should continue.
 184    /// </summary>
 185    public bool ContinueRunning {
 186      get { return continueRunning_; }
 187      set { continueRunning_ = value; }
 188    }
 189
 190    #region Instance Fields
 191    string name_;
 192    Exception exception_;
 193    bool continueRunning_;
 194    #endregion
 195  }
 196
 197  #endregion
 198
 199  #region Delegates
 200  /// <summary>
 201  /// Delegate invoked before starting to process a file.
 202  /// </summary>
 203  /// <param name="sender">The source of the event</param>
 204  /// <param name="e">The event arguments.</param>
 205  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);
 206
 207  /// <summary>
 208  /// Delegate invoked during processing of a file or directory
 209  /// </summary>
 210  /// <param name="sender">The source of the event</param>
 211  /// <param name="e">The event arguments.</param>
 212  public delegate void ProgressHandler(object sender, ProgressEventArgs e);
 213
 214  /// <summary>
 215  /// Delegate invoked when a file has been completely processed.
 216  /// </summary>
 217  /// <param name="sender">The source of the event</param>
 218  /// <param name="e">The event arguments.</param>
 219  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);
 220
 221  /// <summary>
 222  /// Delegate invoked when a directory failure is detected.
 223  /// </summary>
 224  /// <param name="sender">The source of the event</param>
 225  /// <param name="e">The event arguments.</param>
 226  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);
 227
 228  /// <summary>
 229  /// Delegate invoked when a file failure is detected.
 230  /// </summary>
 231  /// <param name="sender">The source of the event</param>
 232  /// <param name="e">The event arguments.</param>
 233  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);
 234  #endregion
 235
 236  /// <summary>
 237  /// FileSystemScanner provides facilities scanning of files and directories.
 238  /// </summary>
 239  public class FileSystemScanner
 240  {
 241    #region Constructors
 242    /// <summary>
 243    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 244    /// </summary>
 245    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>
 0246    public FileSystemScanner(string filter)
 247    {
 0248      fileFilter_ = new PathFilter(filter);
 0249    }
 250
 251    /// <summary>
 252    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 253    /// </summary>
 254    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
 255    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>
 4256    public FileSystemScanner(string fileFilter, string directoryFilter)
 257    {
 4258      fileFilter_ = new PathFilter(fileFilter);
 4259      directoryFilter_ = new PathFilter(directoryFilter);
 4260    }
 261
 262    /// <summary>
 263    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 264    /// </summary>
 265    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
 0266    public FileSystemScanner(IScanFilter fileFilter)
 267    {
 0268      fileFilter_ = fileFilter;
 0269    }
 270
 271    /// <summary>
 272    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 273    /// </summary>
 274    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>
 275    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>
 0276    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)
 277    {
 0278      fileFilter_ = fileFilter;
 0279      directoryFilter_ = directoryFilter;
 0280    }
 281    #endregion
 282
 283    #region Delegates
 284    /// <summary>
 285    /// Delegate to invoke when a directory is processed.
 286    /// </summary>
 287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;
 288
 289    /// <summary>
 290    /// Delegate to invoke when a file is processed.
 291    /// </summary>
 292    public ProcessFileHandler ProcessFile;
 293
 294    /// <summary>
 295    /// Delegate to invoke when processing for a file has finished.
 296    /// </summary>
 297    public CompletedFileHandler CompletedFile;
 298
 299    /// <summary>
 300    /// Delegate to invoke when a directory failure is detected.
 301    /// </summary>
 302    public DirectoryFailureHandler DirectoryFailure;
 303
 304    /// <summary>
 305    /// Delegate to invoke when a file failure is detected.
 306    /// </summary>
 307    public FileFailureHandler FileFailure;
 308    #endregion
 309
 310    /// <summary>
 311    /// Raise the DirectoryFailure event.
 312    /// </summary>
 313    /// <param name="directory">The directory name.</param>
 314    /// <param name="e">The exception detected.</param>
 315    bool OnDirectoryFailure(string directory, Exception e)
 316    {
 0317      DirectoryFailureHandler handler = DirectoryFailure;
 0318      bool result = (handler != null);
 0319       if (result) {
 0320        var args = new ScanFailureEventArgs(directory, e);
 0321        handler(this, args);
 0322        alive_ = args.ContinueRunning;
 323      }
 0324      return result;
 325    }
 326
 327    /// <summary>
 328    /// Raise the FileFailure event.
 329    /// </summary>
 330    /// <param name="file">The file name.</param>
 331    /// <param name="e">The exception detected.</param>
 332    bool OnFileFailure(string file, Exception e)
 333    {
 0334      FileFailureHandler handler = FileFailure;
 335
 0336      bool result = (handler != null);
 337
 0338       if (result) {
 0339        var args = new ScanFailureEventArgs(file, e);
 0340        FileFailure(this, args);
 0341        alive_ = args.ContinueRunning;
 342      }
 0343      return result;
 344    }
 345
 346    /// <summary>
 347    /// Raise the ProcessFile event.
 348    /// </summary>
 349    /// <param name="file">The file name.</param>
 350    void OnProcessFile(string file)
 351    {
 4352      ProcessFileHandler handler = ProcessFile;
 353
 4354       if (handler != null) {
 4355        var args = new ScanEventArgs(file);
 4356        handler(this, args);
 4357        alive_ = args.ContinueRunning;
 358      }
 4359    }
 360
 361    /// <summary>
 362    /// Raise the complete file event
 363    /// </summary>
 364    /// <param name="file">The file name</param>
 365    void OnCompleteFile(string file)
 366    {
 0367      CompletedFileHandler handler = CompletedFile;
 368
 0369       if (handler != null) {
 0370        var args = new ScanEventArgs(file);
 0371        handler(this, args);
 0372        alive_ = args.ContinueRunning;
 373      }
 0374    }
 375
 376    /// <summary>
 377    /// Raise the ProcessDirectory event.
 378    /// </summary>
 379    /// <param name="directory">The directory name.</param>
 380    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>
 381    void OnProcessDirectory(string directory, bool hasMatchingFiles)
 382    {
 4383      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;
 384
 4385       if (handler != null) {
 0386        var args = new DirectoryEventArgs(directory, hasMatchingFiles);
 0387        handler(this, args);
 0388        alive_ = args.ContinueRunning;
 389      }
 4390    }
 391
 392    /// <summary>
 393    /// Scan a directory.
 394    /// </summary>
 395    /// <param name="directory">The base directory to scan.</param>
 396    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>
 397    public void Scan(string directory, bool recurse)
 398    {
 4399      alive_ = true;
 4400      ScanDir(directory, recurse);
 4401    }
 402
 403    void ScanDir(string directory, bool recurse)
 404    {
 405
 406      try {
 4407        string[] names = System.IO.Directory.GetFiles(directory);
 4408        bool hasMatch = false;
 28302409         for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {
 14147410           if (!fileFilter_.IsMatch(names[fileIndex])) {
 14143411            names[fileIndex] = null;
 14143412          } else {
 4413            hasMatch = true;
 414          }
 415        }
 416
 4417        OnProcessDirectory(directory, hasMatch);
 418
 4419         if (alive_ && hasMatch) {
 28302420          foreach (string fileName in names) {
 421            try {
 14147422               if (fileName != null) {
 4423                OnProcessFile(fileName);
 4424                 if (!alive_) {
 0425                  break;
 426                }
 427              }
 14147428            } catch (Exception e) {
 0429               if (!OnFileFailure(fileName, e)) {
 0430                throw;
 431              }
 0432            }
 433          }
 434        }
 4435      } catch (Exception e) {
 0436         if (!OnDirectoryFailure(directory, e)) {
 0437          throw;
 438        }
 0439      }
 440
 4441       if (alive_ && recurse) {
 442        try {
 0443          string[] names = System.IO.Directory.GetDirectories(directory);
 0444          foreach (string fulldir in names) {
 0445             if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {
 0446              ScanDir(fulldir, true);
 0447               if (!alive_) {
 448                break;
 449              }
 450            }
 451          }
 0452        } catch (Exception e) {
 0453           if (!OnDirectoryFailure(directory, e)) {
 0454            throw;
 455          }
 0456        }
 457      }
 4458    }
 459
 460    #region Instance Fields
 461    /// <summary>
 462    /// The file filter currently in use.
 463    /// </summary>
 464    IScanFilter fileFilter_;
 465    /// <summary>
 466    /// The directory filter currently in use.
 467    /// </summary>
 468    IScanFilter directoryFilter_;
 469    /// <summary>
 470    /// Flag indicating if scanning should continue running.
 471    /// </summary>
 472    bool alive_;
 473    #endregion
 474  }
 475}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_GZip.htm b/docs/opencover/ICSharpCode.SharpZipLib_GZip.htm new file mode 100644 index 000000000..b0a579d5f --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_GZip.htm @@ -0,0 +1,109 @@ + + + + +ICSharpCode.SharpZipLib.GZip.GZip - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.GZip.GZip
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GZip.cs
Covered lines:0
Uncovered lines:20
Coverable lines:20
Total lines:66
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
Decompress(...)500
Compress(...)500
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GZip.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.GZip
 5{
 6  /// <summary>
 7  /// An example class to demonstrate compression and decompression of GZip streams.
 8  /// </summary>
 9  public static class GZip
 10  {
 11    /// <summary>
 12    /// Decompress the <paramref name="inStream">input</paramref> writing
 13    /// uncompressed data to the <paramref name="outStream">output stream</paramref>
 14    /// </summary>
 15    /// <param name="inStream">The readable stream containing data to decompress.</param>
 16    /// <param name="outStream">The output stream to receive the decompressed data.</param>
 17    /// <param name="isStreamOwner">Both streams are closed on completion if true.</param>
 18    public static void Decompress(Stream inStream, Stream outStream, bool isStreamOwner)
 19    {
 020       if (inStream == null || outStream == null) {
 021        throw new Exception("Null Stream");
 22      }
 23
 24      try {
 025        using (GZipInputStream bzipInput = new GZipInputStream(inStream)) {
 026          bzipInput.IsStreamOwner = isStreamOwner;
 027          Core.StreamUtils.Copy(bzipInput, outStream, new byte[4096]);
 028        }
 29      } finally {
 030         if (isStreamOwner) {
 31          // inStream is closed by the GZipInputStream if stream owner
 032          outStream.Close();
 33        }
 034      }
 035    }
 36
 37    /// <summary>
 38    /// Compress the <paramref name="inStream">input stream</paramref> sending
 39    /// result data to <paramref name="outStream">output stream</paramref>
 40    /// </summary>
 41    /// <param name="inStream">The readable stream to compress.</param>
 42    /// <param name="outStream">The output stream to receive the compressed data.</param>
 43    /// <param name="isStreamOwner">Both streams are closed on completion if true.</param>
 44    /// <param name="level">Block size acts as compression level (1 to 9) with 1 giving
 45    /// the lowest compression and 9 the highest.</param>
 46    public static void Compress(Stream inStream, Stream outStream, bool isStreamOwner, int level)
 47    {
 048       if (inStream == null || outStream == null) {
 049        throw new Exception("Null Stream");
 50      }
 51
 52      try {
 053        using (GZipOutputStream bzipOutput = new GZipOutputStream(outStream, level)) {
 054          bzipOutput.IsStreamOwner = isStreamOwner;
 055          Core.StreamUtils.Copy(inStream, bzipOutput, new byte[4096]);
 056        }
 57      } finally {
 058         if (isStreamOwner) {
 59          // outStream is closed by the GZipOutputStream if stream owner
 060          inStream.Close();
 61        }
 062      }
 063    }
 64
 65  }
 66}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_GZipConstants.htm b/docs/opencover/ICSharpCode.SharpZipLib_GZipConstants.htm new file mode 100644 index 000000000..08e7a5e30 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_GZipConstants.htm @@ -0,0 +1,99 @@ + + + + +ICSharpCode.SharpZipLib.GZip.GZipConstants - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.GZip.GZipConstants
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GZipConstants.cs
Covered lines:0
Uncovered lines:2
Coverable lines:2
Total lines:58
Line coverage:0%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GZipConstants.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1namespace ICSharpCode.SharpZipLib.GZip
 2{
 3  /// <summary>
 4  /// This class contains constants used for gzip.
 5  /// </summary>
 6  sealed public class GZipConstants
 7  {
 8    /// <summary>
 9    /// Magic number found at start of GZIP header
 10    /// </summary>
 11    public const int GZIP_MAGIC = 0x1F8B;
 12
 13    /*  The flag byte is divided into individual bits as follows:
 14
 15      bit 0   FTEXT
 16      bit 1   FHCRC
 17      bit 2   FEXTRA
 18      bit 3   FNAME
 19      bit 4   FCOMMENT
 20      bit 5   reserved
 21      bit 6   reserved
 22      bit 7   reserved
 23     */
 24
 25    /// <summary>
 26    /// Flag bit mask for text
 27    /// </summary>
 28    public const int FTEXT = 0x1;
 29
 30    /// <summary>
 31    /// Flag bitmask for Crc
 32    /// </summary>
 33    public const int FHCRC = 0x2;
 34
 35    /// <summary>
 36    /// Flag bit mask for extra
 37    /// </summary>
 38    public const int FEXTRA = 0x4;
 39
 40    /// <summary>
 41    /// flag bitmask for name
 42    /// </summary>
 43    public const int FNAME = 0x8;
 44
 45    /// <summary>
 46    /// flag bit mask indicating comment is present
 47    /// </summary>
 48    public const int FCOMMENT = 0x10;
 49
 50    /// <summary>
 51    /// Initialise default instance.
 52    /// </summary>
 53    /// <remarks>Constructor is private to prevent instances being created.</remarks>
 054    GZipConstants()
 55    {
 056    }
 57  }
 58}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_GZipException.htm b/docs/opencover/ICSharpCode.SharpZipLib_GZipException.htm new file mode 100644 index 000000000..6599d235c --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_GZipException.htm @@ -0,0 +1,92 @@ + + + + +ICSharpCode.SharpZipLib.GZip.GZipException - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.GZip.GZipException
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GZipException.cs
Covered lines:0
Uncovered lines:8
Coverable lines:8
Total lines:48
Line coverage:0%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor()100
.ctor(...)100
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GZipException.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Runtime.Serialization;
 3
 4namespace ICSharpCode.SharpZipLib.GZip
 5{
 6  /// <summary>
 7  /// GZipException represents exceptions specific to GZip classes and code.
 8  /// </summary>
 9  [Serializable]
 10  public class GZipException : SharpZipBaseException
 11  {
 12    /// <summary>
 13    /// Deserialization constructor
 14    /// </summary>
 15    /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
 16    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
 17    protected GZipException(SerializationInfo info, StreamingContext context)
 018      : base(info, context)
 19    {
 020    }
 21
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="GZipException" />.
 24    /// </summary>
 025    public GZipException()
 26    {
 027    }
 28
 29    /// <summary>
 30    /// Initialise a new instance of <see cref="GZipException" /> with its message string.
 31    /// </summary>
 32    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 33    public GZipException(string message)
 034      : base(message)
 35    {
 036    }
 37
 38    /// <summary>
 39    /// Initialise a new instance of <see cref="GZipException" />.
 40    /// </summary>
 41    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 42    /// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
 43    public GZipException(string message, Exception innerException)
 044      : base(message, innerException)
 45    {
 046    }
 47  }
 48}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_GZipInputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_GZipInputStream.htm new file mode 100644 index 000000000..c3440d273 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_GZipInputStream.htm @@ -0,0 +1,376 @@ + + + + +ICSharpCode.SharpZipLib.GZip.GZipInputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.GZip.GZipInputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GzipInputStream.cs
Covered lines:4
Uncovered lines:104
Coverable lines:108
Total lines:330
Line coverage:3.7%
Branch coverage:0%
+

Metrics

+ + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)1100100
Read(...)500
ReadHeader()2800
ReadFooter()500
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GzipInputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using ICSharpCode.SharpZipLib.Checksum;
 4using ICSharpCode.SharpZipLib.Zip.Compression;
 5using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 6
 7namespace ICSharpCode.SharpZipLib.GZip
 8{
 9
 10  /// <summary>
 11  /// This filter stream is used to decompress a "GZIP" format stream.
 12  /// The "GZIP" format is described baseInputStream RFC 1952.
 13  ///
 14  /// author of the original java version : John Leuner
 15  /// </summary>
 16  /// <example> This sample shows how to unzip a gzipped file
 17  /// <code>
 18  /// using System;
 19  /// using System.IO;
 20  ///
 21  /// using ICSharpCode.SharpZipLib.Core;
 22  /// using ICSharpCode.SharpZipLib.GZip;
 23  ///
 24  /// class MainClass
 25  /// {
 26  ///   public static void Main(string[] args)
 27  ///   {
 28  ///      using (Stream inStream = new GZipInputStream(File.OpenRead(args[0])))
 29  ///      using (FileStream outStream = File.Create(Path.GetFileNameWithoutExtension(args[0]))) {
 30  ///        byte[] buffer = new byte[4096];
 31  ///        StreamUtils.Copy(inStream, outStream, buffer);
 32  ///     }
 33  ///   }
 34  /// }
 35  /// </code>
 36  /// </example>
 37  public class GZipInputStream : InflaterInputStream
 38  {
 39    #region Instance Fields
 40    /// <summary>
 41    /// CRC-32 value for uncompressed data
 42    /// </summary>
 43    protected Crc32 crc;
 44
 45    /// <summary>
 46    /// Flag to indicate if we've read the GZIP header yet for the current member (block of compressed data).
 47    /// This is tracked per-block as the file is parsed.
 48    /// </summary>
 49    bool readGZIPHeader;
 50    #endregion
 51
 52    #region Constructors
 53    /// <summary>
 54    /// Creates a GZipInputStream with the default buffer size
 55    /// </summary>
 56    /// <param name="baseInputStream">
 57    /// The stream to read compressed data from (baseInputStream GZIP format)
 58    /// </param>
 59    public GZipInputStream(Stream baseInputStream)
 260      : this(baseInputStream, 4096)
 61    {
 262    }
 63
 64    /// <summary>
 65    /// Creates a GZIPInputStream with the specified buffer size
 66    /// </summary>
 67    /// <param name="baseInputStream">
 68    /// The stream to read compressed data from (baseInputStream GZIP format)
 69    /// </param>
 70    /// <param name="size">
 71    /// Size of the buffer to use
 72    /// </param>
 73    public GZipInputStream(Stream baseInputStream, int size)
 274      : base(baseInputStream, new Inflater(true), size)
 75    {
 276    }
 77    #endregion
 78
 79    #region Stream overrides
 80    /// <summary>
 81    /// Reads uncompressed data into an array of bytes
 82    /// </summary>
 83    /// <param name="buffer">
 84    /// The buffer to read uncompressed data into
 85    /// </param>
 86    /// <param name="offset">
 87    /// The offset indicating where the data should be placed
 88    /// </param>
 89    /// <param name="count">
 90    /// The number of uncompressed bytes to be read
 91    /// </param>
 92    /// <returns>Returns the number of bytes actually read.</returns>
 93    public override int Read(byte[] buffer, int offset, int count)
 94    {
 95      // A GZIP file can contain multiple blocks of compressed data, although this is quite rare.
 96      // A compressed block could potentially be empty, so we need to loop until we reach EOF or
 97      // we find data.
 98      while (true) {
 99
 100        // If we haven't read the header for this block, read it
 0101         if (!readGZIPHeader) {
 102
 103          // Try to read header. If there is no header (0 bytes available), this is EOF. If there is
 104          // an incomplete header, this will throw an exception.
 0105           if (!ReadHeader()) {
 0106            return 0;
 107          }
 108        }
 109
 110        // Try to read compressed data
 0111        int bytesRead = base.Read(buffer, offset, count);
 0112         if (bytesRead > 0) {
 0113          crc.Update(buffer, offset, bytesRead);
 114        }
 115
 116        // If this is the end of stream, read the footer
 0117         if (inf.IsFinished) {
 0118          ReadFooter();
 119        }
 120
 0121         if (bytesRead > 0) {
 0122          return bytesRead;
 123        }
 124      }
 125    }
 126    #endregion
 127
 128    #region Support routines
 129    bool ReadHeader()
 130    {
 131      // Initialize CRC for this block
 0132      crc = new Crc32();
 133
 134      // Make sure there is data in file. We can't rely on ReadLeByte() to fill the buffer, as this could be EOF,
 135      // which is fine, but ReadLeByte() throws an exception if it doesn't find data, so we do this part ourselves.
 0136       if (inputBuffer.Available <= 0) {
 0137        inputBuffer.Fill();
 0138         if (inputBuffer.Available <= 0) {
 139          // No header, EOF.
 0140          return false;
 141        }
 142      }
 143
 144      // 1. Check the two magic bytes
 0145      var headCRC = new Crc32();
 0146      int magic = inputBuffer.ReadLeByte();
 147
 0148       if (magic < 0) {
 0149        throw new EndOfStreamException("EOS reading GZIP header");
 150      }
 151
 0152      headCRC.Update(magic);
 0153       if (magic != (GZipConstants.GZIP_MAGIC >> 8)) {
 0154        throw new GZipException("Error GZIP header, first magic byte doesn't match");
 155      }
 156
 157      //magic = baseInputStream.ReadByte();
 0158      magic = inputBuffer.ReadLeByte();
 159
 0160       if (magic < 0) {
 0161        throw new EndOfStreamException("EOS reading GZIP header");
 162      }
 163
 0164       if (magic != (GZipConstants.GZIP_MAGIC & 0xFF)) {
 0165        throw new GZipException("Error GZIP header,  second magic byte doesn't match");
 166      }
 167
 0168      headCRC.Update(magic);
 169
 170      // 2. Check the compression type (must be 8)
 0171      int compressionType = inputBuffer.ReadLeByte();
 172
 0173       if (compressionType < 0) {
 0174        throw new EndOfStreamException("EOS reading GZIP header");
 175      }
 176
 0177       if (compressionType != 8) {
 0178        throw new GZipException("Error GZIP header, data not in deflate format");
 179      }
 0180      headCRC.Update(compressionType);
 181
 182      // 3. Check the flags
 0183      int flags = inputBuffer.ReadLeByte();
 0184       if (flags < 0) {
 0185        throw new EndOfStreamException("EOS reading GZIP header");
 186      }
 0187      headCRC.Update(flags);
 188
 189      /*    This flag byte is divided into individual bits as follows:
 190
 191      bit 0   FTEXT
 192      bit 1   FHCRC
 193      bit 2   FEXTRA
 194      bit 3   FNAME
 195      bit 4   FCOMMENT
 196      bit 5   reserved
 197      bit 6   reserved
 198      bit 7   reserved
 199      */
 200
 201      // 3.1 Check the reserved bits are zero
 202
 0203       if ((flags & 0xE0) != 0) {
 0204        throw new GZipException("Reserved flag bits in GZIP header != 0");
 205      }
 206
 207      // 4.-6. Skip the modification time, extra flags, and OS type
 0208       for (int i = 0; i < 6; i++) {
 0209        int readByte = inputBuffer.ReadLeByte();
 0210         if (readByte < 0) {
 0211          throw new EndOfStreamException("EOS reading GZIP header");
 212        }
 0213        headCRC.Update(readByte);
 214      }
 215
 216      // 7. Read extra field
 0217       if ((flags & GZipConstants.FEXTRA) != 0) {
 218
 219        // XLEN is total length of extra subfields, we will skip them all
 220        int len1, len2;
 0221        len1 = inputBuffer.ReadLeByte();
 0222        len2 = inputBuffer.ReadLeByte();
 0223         if ((len1 < 0) || (len2 < 0)) {
 0224          throw new EndOfStreamException("EOS reading GZIP header");
 225        }
 0226        headCRC.Update(len1);
 0227        headCRC.Update(len2);
 228
 0229        int extraLen = (len2 << 8) | len1;      // gzip is LSB first
 0230         for (int i = 0; i < extraLen; i++) {
 0231          int readByte = inputBuffer.ReadLeByte();
 0232           if (readByte < 0) {
 0233            throw new EndOfStreamException("EOS reading GZIP header");
 234          }
 0235          headCRC.Update(readByte);
 236        }
 237      }
 238
 239      // 8. Read file name
 0240       if ((flags & GZipConstants.FNAME) != 0) {
 241        int readByte;
 0242         while ((readByte = inputBuffer.ReadLeByte()) > 0) {
 0243          headCRC.Update(readByte);
 244        }
 245
 0246         if (readByte < 0) {
 0247          throw new EndOfStreamException("EOS reading GZIP header");
 248        }
 0249        headCRC.Update(readByte);
 250      }
 251
 252      // 9. Read comment
 0253       if ((flags & GZipConstants.FCOMMENT) != 0) {
 254        int readByte;
 0255         while ((readByte = inputBuffer.ReadLeByte()) > 0) {
 0256          headCRC.Update(readByte);
 257        }
 258
 0259         if (readByte < 0) {
 0260          throw new EndOfStreamException("EOS reading GZIP header");
 261        }
 262
 0263        headCRC.Update(readByte);
 264      }
 265
 266      // 10. Read header CRC
 0267       if ((flags & GZipConstants.FHCRC) != 0) {
 268        int tempByte;
 0269        int crcval = inputBuffer.ReadLeByte();
 0270         if (crcval < 0) {
 0271          throw new EndOfStreamException("EOS reading GZIP header");
 272        }
 273
 0274        tempByte = inputBuffer.ReadLeByte();
 0275         if (tempByte < 0) {
 0276          throw new EndOfStreamException("EOS reading GZIP header");
 277        }
 278
 0279        crcval = (crcval << 8) | tempByte;
 0280         if (crcval != ((int)headCRC.Value & 0xffff)) {
 0281          throw new GZipException("Header CRC value mismatch");
 282        }
 283      }
 284
 0285      readGZIPHeader = true;
 0286      return true;
 287    }
 288
 289    void ReadFooter()
 290    {
 0291      byte[] footer = new byte[8];
 292
 293      // End of stream; reclaim all bytes from inf, read the final byte count, and reset the inflator
 0294      long bytesRead = inf.TotalOut & 0xffffffff;
 0295      inputBuffer.Available += inf.RemainingInput;
 0296      inf.Reset();
 297
 298      // Read footer from inputBuffer
 0299      int needed = 8;
 0300       while (needed > 0) {
 0301        int count = inputBuffer.ReadClearTextBuffer(footer, 8 - needed, needed);
 0302         if (count <= 0) {
 0303          throw new EndOfStreamException("EOS reading GZIP footer");
 304        }
 0305        needed -= count; // Jewel Jan 16
 306      }
 307
 308      // Calculate CRC
 0309      int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) | ((footer[2] & 0xff) << 16) | (footer[3] << 24);
 0310       if (crcval != (int)crc.Value) {
 0311        throw new GZipException("GZIP crc sum mismatch, theirs \"" + crcval + "\" and ours \"" + (int)crc.Value);
 312      }
 313
 314      // NOTE The total here is the original total modulo 2 ^ 32.
 0315      uint total =
 0316        (uint)((uint)footer[4] & 0xff) |
 0317        (uint)(((uint)footer[5] & 0xff) << 8) |
 0318        (uint)(((uint)footer[6] & 0xff) << 16) |
 0319        (uint)((uint)footer[7] << 24);
 320
 0321       if (bytesRead != total) {
 0322        throw new GZipException("Number of bytes mismatch in footer");
 323      }
 324
 325      // Mark header read as false so if another header exists, we'll continue reading through the file
 0326      readGZIPHeader = false;
 0327    }
 328    #endregion
 329  }
 330}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_GZipOutputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_GZipOutputStream.htm new file mode 100644 index 000000000..4a2396cf9 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_GZipOutputStream.htm @@ -0,0 +1,277 @@ + + + + +ICSharpCode.SharpZipLib.GZip.GZipOutputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.GZip.GZipOutputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GzipOutputStream.cs
Covered lines:63
Uncovered lines:5
Coverable lines:68
Total lines:227
Line coverage:92.6%
Branch coverage:81.2%
+

Metrics

+ + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)1100100
Finalize()1100100
SetLevel(...)200
GetLevel()100
Write(...)3100100
Close()3100100
Finish()3100100
WriteHeader()210066.67
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\GZip\GzipOutputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using ICSharpCode.SharpZipLib.Checksum;
 4using ICSharpCode.SharpZipLib.Zip.Compression;
 5using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 6
 7namespace ICSharpCode.SharpZipLib.GZip
 8{
 9  /// <summary>
 10  /// This filter stream is used to compress a stream into a "GZIP" stream.
 11  /// The "GZIP" format is described in RFC 1952.
 12  ///
 13  /// author of the original java version : John Leuner
 14  /// </summary>
 15  /// <example> This sample shows how to gzip a file
 16  /// <code>
 17  /// using System;
 18  /// using System.IO;
 19  ///
 20  /// using ICSharpCode.SharpZipLib.GZip;
 21  /// using ICSharpCode.SharpZipLib.Core;
 22  ///
 23  /// class MainClass
 24  /// {
 25  ///   public static void Main(string[] args)
 26  ///   {
 27  ///       using (Stream s = new GZipOutputStream(File.Create(args[0] + ".gz")))
 28  ///       using (FileStream fs = File.OpenRead(args[0])) {
 29  ///         byte[] writeData = new byte[4096];
 30  ///         Streamutils.Copy(s, fs, writeData);
 31  ///       }
 32  ///     }
 33  ///   }
 34  /// }
 35  /// </code>
 36  /// </example>
 37  public class GZipOutputStream : DeflaterOutputStream
 38  {
 39    enum OutputState
 40    {
 41      Header,
 42      Footer,
 43      Finished,
 44      Closed,
 45    };
 46
 47    #region Instance Fields
 48    /// <summary>
 49    /// CRC-32 value for uncompressed data
 50    /// </summary>
 951    protected Crc32 crc = new Crc32();
 52    OutputState state_ = OutputState.Header;
 53    #endregion
 54
 55    #region Constructors
 56    /// <summary>
 57    /// Creates a GzipOutputStream with the default buffer size
 58    /// </summary>
 59    /// <param name="baseOutputStream">
 60    /// The stream to read data (to be compressed) from
 61    /// </param>
 62    public GZipOutputStream(Stream baseOutputStream)
 963      : this(baseOutputStream, 4096)
 64    {
 965    }
 66
 67    /// <summary>
 68    /// Creates a GZipOutputStream with the specified buffer size
 69    /// </summary>
 70    /// <param name="baseOutputStream">
 71    /// The stream to read data (to be compressed) from
 72    /// </param>
 73    /// <param name="size">
 74    /// Size of the buffer to use
 75    /// </param>
 976    public GZipOutputStream(Stream baseOutputStream, int size) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_CO
 77    {
 978    }
 79    #endregion
 80
 81    #region Destructor
 82    /// <summary>
 83    /// Ensures that resources are freed and other cleanup operations
 84    /// are performed when the garbage collector reclaims the GZipOutputStream.
 85    /// </summary>
 86    ~GZipOutputStream()
 87    {
 988      Dispose(false);
 1889    }
 90    #endregion
 91
 92    #region Public API
 93    /// <summary>
 94    /// Sets the active compression level (1-9).  The new level will be activated
 95    /// immediately.
 96    /// </summary>
 97    /// <param name="level">The compression level to set.</param>
 98    /// <exception cref="ArgumentOutOfRangeException">
 99    /// Level specified is not supported.
 100    /// </exception>
 101    /// <see cref="Deflater"/>
 102    public void SetLevel(int level)
 103    {
 0104       if (level < Deflater.BEST_SPEED) {
 0105        throw new ArgumentOutOfRangeException(nameof(level));
 106      }
 0107      deflater_.SetLevel(level);
 0108    }
 109
 110    /// <summary>
 111    /// Get the current compression level.
 112    /// </summary>
 113    /// <returns>The current compression level.</returns>
 114    public int GetLevel()
 115    {
 0116      return deflater_.GetLevel();
 117    }
 118    #endregion
 119
 120    #region Stream overrides
 121    /// <summary>
 122    /// Write given buffer to output updating crc
 123    /// </summary>
 124    /// <param name="buffer">Buffer to write</param>
 125    /// <param name="offset">Offset of first byte in buf to write</param>
 126    /// <param name="count">Number of bytes to write</param>
 127    public override void Write(byte[] buffer, int offset, int count)
 128    {
 3129       if (state_ == OutputState.Header) {
 1130        WriteHeader();
 131      }
 132
 3133       if (state_ != OutputState.Footer) {
 2134        throw new InvalidOperationException("Write not permitted in current state");
 135      }
 136
 1137      crc.Update(buffer, offset, count);
 1138      base.Write(buffer, offset, count);
 1139    }
 140
 141    /// <summary>
 142    /// Writes remaining compressed output data to the output stream
 143    /// and closes it.
 144    /// </summary>
 145    public override void Close()
 146    {
 147      try {
 10148        Finish();
 10149      } finally {
 10150         if (state_ != OutputState.Closed) {
 8151          state_ = OutputState.Closed;
 8152           if (IsStreamOwner) {
 7153            baseOutputStream_.Close();
 154          }
 155        }
 10156      }
 10157    }
 158    #endregion
 159
 160    #region DeflaterOutputStream overrides
 161    /// <summary>
 162    /// Finish compression and write any footer information required to stream
 163    /// </summary>
 164    public override void Finish()
 165    {
 166      // If no data has been written a header should be added.
 13167       if (state_ == OutputState.Header) {
 8168        WriteHeader();
 169      }
 170
 13171       if (state_ == OutputState.Footer) {
 9172        state_ = OutputState.Finished;
 9173        base.Finish();
 174
 9175        var totalin = (uint)(deflater_.TotalIn & 0xffffffff);
 9176        var crcval = (uint)(crc.Value & 0xffffffff);
 177
 178        byte[] gzipFooter;
 179
 180        unchecked {
 9181          gzipFooter = new byte[] {
 9182          (byte) crcval, (byte) (crcval >> 8),
 9183          (byte) (crcval >> 16), (byte) (crcval >> 24),
 9184
 9185          (byte) totalin, (byte) (totalin >> 8),
 9186          (byte) (totalin >> 16), (byte) (totalin >> 24)
 9187        };
 188        }
 189
 9190        baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length);
 191      }
 13192    }
 193    #endregion
 194
 195    #region Support Routines
 196    void WriteHeader()
 197    {
 9198       if (state_ == OutputState.Header) {
 9199        state_ = OutputState.Footer;
 200
 9201        var mod_time = (int)((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000L);  // Ticks give back 100
 9202        byte[] gzipHeader = {
 9203          // The two magic bytes
 9204          (byte) (GZipConstants.GZIP_MAGIC >> 8), (byte) (GZipConstants.GZIP_MAGIC & 0xff),
 9205
 9206          // The compression type
 9207          (byte) Deflater.DEFLATED,
 9208
 9209          // The flags (not set)
 9210          0,
 9211
 9212          // The modification time
 9213          (byte) mod_time, (byte) (mod_time >> 8),
 9214          (byte) (mod_time >> 16), (byte) (mod_time >> 24),
 9215
 9216          // The extra flags
 9217          0,
 9218
 9219          // The OS type (unknown)
 9220          (byte) 255
 9221        };
 9222        baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length);
 223      }
 9224    }
 225    #endregion
 226  }
 227}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_Inflater.htm b/docs/opencover/ICSharpCode.SharpZipLib_Inflater.htm new file mode 100644 index 000000000..204a3f1e7 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_Inflater.htm @@ -0,0 +1,844 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.Inflater - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.Inflater
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Inflater.cs
Covered lines:173
Uncovered lines:57
Coverable lines:230
Total lines:788
Line coverage:75.2%
Branch coverage:59.8%
+

Metrics

+ + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
.ctor(...)3100100
Reset()310066.67
DecodeHeader()573.3366.67
DecodeDict()300
DecodeHuffman()1477.0861.54
DecodeChksum()481.8271.43
Decode()2487.2771.43
SetDictionary(...)100
SetDictionary(...)600
SetInput(...)100
SetInput(...)1100100
Inflate(...)200
Inflate(...)138480
.cctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Inflater.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using ICSharpCode.SharpZipLib.Checksum;
 3using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 4
 5namespace ICSharpCode.SharpZipLib.Zip.Compression
 6{
 7  /// <summary>
 8  /// Inflater is used to decompress data that has been compressed according
 9  /// to the "deflate" standard described in rfc1951.
 10  ///
 11  /// By default Zlib (rfc1950) headers and footers are expected in the input.
 12  /// You can use constructor <code> public Inflater(bool noHeader)</code> passing true
 13  /// if there is no Zlib header information
 14  ///
 15  /// The usage is as following.  First you have to set some input with
 16  /// <code>SetInput()</code>, then Inflate() it.  If inflate doesn't
 17  /// inflate any bytes there may be three reasons:
 18  /// <ul>
 19  /// <li>IsNeedingInput() returns true because the input buffer is empty.
 20  /// You have to provide more input with <code>SetInput()</code>.
 21  /// NOTE: IsNeedingInput() also returns true when, the stream is finished.
 22  /// </li>
 23  /// <li>IsNeedingDictionary() returns true, you have to provide a preset
 24  ///    dictionary with <code>SetDictionary()</code>.</li>
 25  /// <li>IsFinished returns true, the inflater has finished.</li>
 26  /// </ul>
 27  /// Once the first output byte is produced, a dictionary will not be
 28  /// needed at a later stage.
 29  ///
 30  /// author of the original java version : John Leuner, Jochen Hoenicke
 31  /// </summary>
 32  public class Inflater
 33  {
 34    #region Constants/Readonly
 35    /// <summary>
 36    /// Copy lengths for literal codes 257..285
 37    /// </summary>
 138    static readonly int[] CPLENS = {
 139                  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
 140                  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
 141                };
 42
 43    /// <summary>
 44    /// Extra bits for literal codes 257..285
 45    /// </summary>
 146    static readonly int[] CPLEXT = {
 147                  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
 148                  3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
 149                };
 50
 51    /// <summary>
 52    /// Copy offsets for distance codes 0..29
 53    /// </summary>
 154    static readonly int[] CPDIST = {
 155                1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
 156                257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
 157                8193, 12289, 16385, 24577
 158                };
 59
 60    /// <summary>
 61    /// Extra bits for distance codes
 62    /// </summary>
 163    static readonly int[] CPDEXT = {
 164                0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
 165                7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
 166                12, 12, 13, 13
 167                };
 68
 69    /// <summary>
 70    /// These are the possible states for an inflater
 71    /// </summary>
 72    const int DECODE_HEADER = 0;
 73    const int DECODE_DICT = 1;
 74    const int DECODE_BLOCKS = 2;
 75    const int DECODE_STORED_LEN1 = 3;
 76    const int DECODE_STORED_LEN2 = 4;
 77    const int DECODE_STORED = 5;
 78    const int DECODE_DYN_HEADER = 6;
 79    const int DECODE_HUFFMAN = 7;
 80    const int DECODE_HUFFMAN_LENBITS = 8;
 81    const int DECODE_HUFFMAN_DIST = 9;
 82    const int DECODE_HUFFMAN_DISTBITS = 10;
 83    const int DECODE_CHKSUM = 11;
 84    const int FINISHED = 12;
 85    #endregion
 86
 87    #region Instance Fields
 88    /// <summary>
 89    /// This variable contains the current state.
 90    /// </summary>
 91    int mode;
 92
 93    /// <summary>
 94    /// The adler checksum of the dictionary or of the decompressed
 95    /// stream, as it is written in the header resp. footer of the
 96    /// compressed stream.
 97    /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
 98    /// </summary>
 99    int readAdler;
 100
 101    /// <summary>
 102    /// The number of bits needed to complete the current state.  This
 103    /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
 104    /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
 105    /// </summary>
 106    int neededBits;
 107    int repLength;
 108    int repDist;
 109    int uncomprLen;
 110
 111    /// <summary>
 112    /// True, if the last block flag was set in the last block of the
 113    /// inflated stream.  This means that the stream ends after the
 114    /// current block.
 115    /// </summary>
 116    bool isLastBlock;
 117
 118    /// <summary>
 119    /// The total number of inflated bytes.
 120    /// </summary>
 121    long totalOut;
 122
 123    /// <summary>
 124    /// The total number of bytes set with setInput().  This is not the
 125    /// value returned by the TotalIn property, since this also includes the
 126    /// unprocessed input.
 127    /// </summary>
 128    long totalIn;
 129
 130    /// <summary>
 131    /// This variable stores the noHeader flag that was given to the constructor.
 132    /// True means, that the inflated stream doesn't contain a Zlib header or
 133    /// footer.
 134    /// </summary>
 135    bool noHeader;
 136    readonly StreamManipulator input;
 137    OutputWindow outputWindow;
 138    InflaterDynHeader dynHeader;
 139    InflaterHuffmanTree litlenTree, distTree;
 140    Adler32 adler;
 141    #endregion
 142
 143    #region Constructors
 144    /// <summary>
 145    /// Creates a new inflater or RFC1951 decompressor
 146    /// RFC1950/Zlib headers and footers will be expected in the input data
 147    /// </summary>
 3148    public Inflater() : this(false)
 149    {
 3150    }
 151
 152    /// <summary>
 153    /// Creates a new inflater.
 154    /// </summary>
 155    /// <param name="noHeader">
 156    /// True if no RFC1950/Zlib header and footer fields are expected in the input data
 157    ///
 158    /// This is used for GZIPed/Zipped input.
 159    ///
 160    /// For compatibility with
 161    /// Sun JDK you should provide one byte of input more than needed in
 162    /// this case.
 163    /// </param>
 435164    public Inflater(bool noHeader)
 165    {
 435166      this.noHeader = noHeader;
 435167      this.adler = new Adler32();
 435168      input = new StreamManipulator();
 435169      outputWindow = new OutputWindow();
 435170       mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
 435171    }
 172    #endregion
 173
 174    /// <summary>
 175    /// Resets the inflater so that a new stream can be decompressed.  All
 176    /// pending input and output will be discarded.
 177    /// </summary>
 178    public void Reset()
 179    {
 41180       mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
 41181      totalIn = 0;
 41182      totalOut = 0;
 41183      input.Reset();
 41184      outputWindow.Reset();
 41185      dynHeader = null;
 41186      litlenTree = null;
 41187      distTree = null;
 41188      isLastBlock = false;
 41189      adler.Reset();
 41190    }
 191
 192    /// <summary>
 193    /// Decodes a zlib/RFC1950 header.
 194    /// </summary>
 195    /// <returns>
 196    /// False if more input is needed.
 197    /// </returns>
 198    /// <exception cref="SharpZipBaseException">
 199    /// The header is invalid.
 200    /// </exception>
 201    private bool DecodeHeader()
 202    {
 22203      int header = input.PeekBits(16);
 22204       if (header < 0) {
 11205        return false;
 206      }
 11207      input.DropBits(16);
 208
 209      // The header is written in "wrong" byte order
 11210      header = ((header << 8) | (header >> 8)) & 0xffff;
 11211       if (header % 31 != 0) {
 0212        throw new SharpZipBaseException("Header checksum illegal");
 213      }
 214
 11215       if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) {
 0216        throw new SharpZipBaseException("Compression Method unknown");
 217      }
 218
 219      /* Maximum size of the backwards window in bits.
 220      * We currently ignore this, but we could use it to make the
 221      * inflater window more space efficient. On the other hand the
 222      * full window (15 bits) is needed most times, anyway.
 223      int max_wbits = ((header & 0x7000) >> 12) + 8;
 224      */
 225
 11226       if ((header & 0x0020) == 0) { // Dictionary flag?
 11227        mode = DECODE_BLOCKS;
 11228      } else {
 0229        mode = DECODE_DICT;
 0230        neededBits = 32;
 231      }
 11232      return true;
 233    }
 234
 235    /// <summary>
 236    /// Decodes the dictionary checksum after the deflate header.
 237    /// </summary>
 238    /// <returns>
 239    /// False if more input is needed.
 240    /// </returns>
 241    private bool DecodeDict()
 242    {
 0243       while (neededBits > 0) {
 0244        int dictByte = input.PeekBits(8);
 0245         if (dictByte < 0) {
 0246          return false;
 247        }
 0248        input.DropBits(8);
 0249        readAdler = (readAdler << 8) | dictByte;
 0250        neededBits -= 8;
 251      }
 0252      return false;
 253    }
 254
 255    /// <summary>
 256    /// Decodes the huffman encoded symbols in the input stream.
 257    /// </summary>
 258    /// <returns>
 259    /// false if more input is needed, true if output window is
 260    /// full or the current block ends.
 261    /// </returns>
 262    /// <exception cref="SharpZipBaseException">
 263    /// if deflated stream is invalid.
 264    /// </exception>
 265    private bool DecodeHuffman()
 266    {
 371267      int free = outputWindow.GetFreeSpace();
 468268       while (free >= 258) {
 269        int symbol;
 468270         switch (mode) {
 271          case DECODE_HUFFMAN:
 272            // This is the inner loop so it is optimized a bit
 9697273             while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0) {
 9229274              outputWindow.Write(symbol);
 9229275               if (--free < 258) {
 0276                return true;
 277              }
 278            }
 279
 468280             if (symbol < 257) {
 371281               if (symbol < 0) {
 0282                return false;
 283              } else {
 284                // symbol == 256: end of block
 371285                distTree = null;
 371286                litlenTree = null;
 371287                mode = DECODE_BLOCKS;
 371288                return true;
 289              }
 290            }
 291
 292            try {
 97293              repLength = CPLENS[symbol - 257];
 97294              neededBits = CPLEXT[symbol - 257];
 97295            } catch (Exception) {
 0296              throw new SharpZipBaseException("Illegal rep length code");
 297            }
 298            goto case DECODE_HUFFMAN_LENBITS; // fall through
 299
 300          case DECODE_HUFFMAN_LENBITS:
 97301             if (neededBits > 0) {
 25302              mode = DECODE_HUFFMAN_LENBITS;
 25303              int i = input.PeekBits(neededBits);
 25304               if (i < 0) {
 0305                return false;
 306              }
 25307              input.DropBits(neededBits);
 25308              repLength += i;
 309            }
 97310            mode = DECODE_HUFFMAN_DIST;
 311            goto case DECODE_HUFFMAN_DIST; // fall through
 312
 313          case DECODE_HUFFMAN_DIST:
 97314            symbol = distTree.GetSymbol(input);
 97315             if (symbol < 0) {
 0316              return false;
 317            }
 318
 319            try {
 97320              repDist = CPDIST[symbol];
 97321              neededBits = CPDEXT[symbol];
 97322            } catch (Exception) {
 0323              throw new SharpZipBaseException("Illegal rep dist code");
 324            }
 325
 326            goto case DECODE_HUFFMAN_DISTBITS; // fall through
 327
 328          case DECODE_HUFFMAN_DISTBITS:
 97329             if (neededBits > 0) {
 68330              mode = DECODE_HUFFMAN_DISTBITS;
 68331              int i = input.PeekBits(neededBits);
 68332               if (i < 0) {
 0333                return false;
 334              }
 68335              input.DropBits(neededBits);
 68336              repDist += i;
 337            }
 338
 97339            outputWindow.Repeat(repLength, repDist);
 97340            free -= repLength;
 97341            mode = DECODE_HUFFMAN;
 97342            break;
 343
 344          default:
 0345            throw new SharpZipBaseException("Inflater unknown mode");
 346        }
 347      }
 0348      return true;
 349    }
 350
 351    /// <summary>
 352    /// Decodes the adler checksum after the deflate stream.
 353    /// </summary>
 354    /// <returns>
 355    /// false if more input is needed.
 356    /// </returns>
 357    /// <exception cref="SharpZipBaseException">
 358    /// If checksum doesn't match.
 359    /// </exception>
 360    private bool DecodeChksum()
 361    {
 5362       while (neededBits > 0) {
 4363        int chkByte = input.PeekBits(8);
 4364         if (chkByte < 0) {
 0365          return false;
 366        }
 4367        input.DropBits(8);
 4368        readAdler = (readAdler << 8) | chkByte;
 4369        neededBits -= 8;
 370      }
 371
 1372       if ((int)adler.Value != readAdler) {
 0373        throw new SharpZipBaseException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler);
 374      }
 375
 1376      mode = FINISHED;
 1377      return false;
 378    }
 379
 380    /// <summary>
 381    /// Decodes the deflated stream.
 382    /// </summary>
 383    /// <returns>
 384    /// false if more input is needed, or if finished.
 385    /// </returns>
 386    /// <exception cref="SharpZipBaseException">
 387    /// if deflated stream is invalid.
 388    /// </exception>
 389    private bool Decode()
 390    {
 4422391       switch (mode) {
 392        case DECODE_HEADER:
 22393          return DecodeHeader();
 394
 395        case DECODE_DICT:
 0396          return DecodeDict();
 397
 398        case DECODE_CHKSUM:
 1399          return DecodeChksum();
 400
 401        case DECODE_BLOCKS:
 1412402           if (isLastBlock) {
 387403             if (noHeader) {
 376404              mode = FINISHED;
 376405              return false;
 406            } else {
 11407              input.SkipToByteBoundary();
 11408              neededBits = 32;
 11409              mode = DECODE_CHKSUM;
 11410              return true;
 411            }
 412          }
 413
 1025414          int type = input.PeekBits(3);
 1025415           if (type < 0) {
 362416            return false;
 417          }
 663418          input.DropBits(3);
 419
 663420          isLastBlock |= (type & 1) != 0;
 663421           switch (type >> 1) {
 422            case DeflaterConstants.STORED_BLOCK:
 292423              input.SkipToByteBoundary();
 292424              mode = DECODE_STORED_LEN1;
 292425              break;
 426            case DeflaterConstants.STATIC_TREES:
 370427              litlenTree = InflaterHuffmanTree.defLitLenTree;
 370428              distTree = InflaterHuffmanTree.defDistTree;
 370429              mode = DECODE_HUFFMAN;
 370430              break;
 431            case DeflaterConstants.DYN_TREES:
 1432              dynHeader = new InflaterDynHeader();
 1433              mode = DECODE_DYN_HEADER;
 1434              break;
 435            default:
 0436              throw new SharpZipBaseException("Unknown block type " + type);
 437          }
 663438          return true;
 439
 440        case DECODE_STORED_LEN1: {
 292441             if ((uncomprLen = input.PeekBits(16)) < 0) {
 0442              return false;
 443            }
 292444            input.DropBits(16);
 292445            mode = DECODE_STORED_LEN2;
 446          }
 447          goto case DECODE_STORED_LEN2; // fall through
 448
 449        case DECODE_STORED_LEN2: {
 292450            int nlen = input.PeekBits(16);
 292451             if (nlen < 0) {
 0452              return false;
 453            }
 292454            input.DropBits(16);
 292455             if (nlen != (uncomprLen ^ 0xffff)) {
 0456              throw new SharpZipBaseException("broken uncompressed block");
 457            }
 292458            mode = DECODE_STORED;
 459          }
 460          goto case DECODE_STORED; // fall through
 461
 462        case DECODE_STORED: {
 2280463            int more = outputWindow.CopyStored(input, uncomprLen);
 2280464            uncomprLen -= more;
 2280465             if (uncomprLen == 0) {
 292466              mode = DECODE_BLOCKS;
 292467              return true;
 468            }
 1988469            return !input.IsNeedingInput;
 470          }
 471
 472        case DECODE_DYN_HEADER:
 1473           if (!dynHeader.Decode(input)) {
 0474            return false;
 475          }
 476
 1477          litlenTree = dynHeader.BuildLitLenTree();
 1478          distTree = dynHeader.BuildDistTree();
 1479          mode = DECODE_HUFFMAN;
 480          goto case DECODE_HUFFMAN; // fall through
 481
 482        case DECODE_HUFFMAN:
 483        case DECODE_HUFFMAN_LENBITS:
 484        case DECODE_HUFFMAN_DIST:
 485        case DECODE_HUFFMAN_DISTBITS:
 371486          return DecodeHuffman();
 487
 488        case FINISHED:
 336489          return false;
 490
 491        default:
 0492          throw new SharpZipBaseException("Inflater.Decode unknown mode");
 493      }
 494    }
 495
 496    /// <summary>
 497    /// Sets the preset dictionary.  This should only be called, if
 498    /// needsDictionary() returns true and it should set the same
 499    /// dictionary, that was used for deflating.  The getAdler()
 500    /// function returns the checksum of the dictionary needed.
 501    /// </summary>
 502    /// <param name="buffer">
 503    /// The dictionary.
 504    /// </param>
 505    public void SetDictionary(byte[] buffer)
 506    {
 0507      SetDictionary(buffer, 0, buffer.Length);
 0508    }
 509
 510    /// <summary>
 511    /// Sets the preset dictionary.  This should only be called, if
 512    /// needsDictionary() returns true and it should set the same
 513    /// dictionary, that was used for deflating.  The getAdler()
 514    /// function returns the checksum of the dictionary needed.
 515    /// </summary>
 516    /// <param name="buffer">
 517    /// The dictionary.
 518    /// </param>
 519    /// <param name="index">
 520    /// The index into buffer where the dictionary starts.
 521    /// </param>
 522    /// <param name="count">
 523    /// The number of bytes in the dictionary.
 524    /// </param>
 525    /// <exception cref="System.InvalidOperationException">
 526    /// No dictionary is needed.
 527    /// </exception>
 528    /// <exception cref="SharpZipBaseException">
 529    /// The adler checksum for the buffer is invalid
 530    /// </exception>
 531    public void SetDictionary(byte[] buffer, int index, int count)
 532    {
 0533       if (buffer == null) {
 0534        throw new ArgumentNullException(nameof(buffer));
 535      }
 536
 0537       if (index < 0) {
 0538        throw new ArgumentOutOfRangeException(nameof(index));
 539      }
 540
 0541       if (count < 0) {
 0542        throw new ArgumentOutOfRangeException(nameof(count));
 543      }
 544
 0545       if (!IsNeedingDictionary) {
 0546        throw new InvalidOperationException("Dictionary is not needed");
 547      }
 548
 0549      adler.Update(buffer, index, count);
 550
 0551       if ((int)adler.Value != readAdler) {
 0552        throw new SharpZipBaseException("Wrong adler checksum");
 553      }
 0554      adler.Reset();
 0555      outputWindow.CopyDict(buffer, index, count);
 0556      mode = DECODE_BLOCKS;
 0557    }
 558
 559    /// <summary>
 560    /// Sets the input.  This should only be called, if needsInput()
 561    /// returns true.
 562    /// </summary>
 563    /// <param name="buffer">
 564    /// the input.
 565    /// </param>
 566    public void SetInput(byte[] buffer)
 567    {
 0568      SetInput(buffer, 0, buffer.Length);
 0569    }
 570
 571    /// <summary>
 572    /// Sets the input.  This should only be called, if needsInput()
 573    /// returns true.
 574    /// </summary>
 575    /// <param name="buffer">
 576    /// The source of input data
 577    /// </param>
 578    /// <param name="index">
 579    /// The index into buffer where the input starts.
 580    /// </param>
 581    /// <param name="count">
 582    /// The number of bytes of input to use.
 583    /// </param>
 584    /// <exception cref="System.InvalidOperationException">
 585    /// No input is needed.
 586    /// </exception>
 587    /// <exception cref="System.ArgumentOutOfRangeException">
 588    /// The index and/or count are wrong.
 589    /// </exception>
 590    public void SetInput(byte[] buffer, int index, int count)
 591    {
 1433592      input.SetInput(buffer, index, count);
 1433593      totalIn += (long)count;
 1433594    }
 595
 596    /// <summary>
 597    /// Inflates the compressed stream to the output buffer.  If this
 598    /// returns 0, you should check, whether IsNeedingDictionary(),
 599    /// IsNeedingInput() or IsFinished() returns true, to determine why no
 600    /// further output is produced.
 601    /// </summary>
 602    /// <param name="buffer">
 603    /// the output buffer.
 604    /// </param>
 605    /// <returns>
 606    /// The number of bytes written to the buffer, 0 if no further
 607    /// output can be produced.
 608    /// </returns>
 609    /// <exception cref="System.ArgumentOutOfRangeException">
 610    /// if buffer has length 0.
 611    /// </exception>
 612    /// <exception cref="System.FormatException">
 613    /// if deflated stream is invalid.
 614    /// </exception>
 615    public int Inflate(byte[] buffer)
 616    {
 0617       if (buffer == null) {
 0618        throw new ArgumentNullException(nameof(buffer));
 619      }
 620
 0621      return Inflate(buffer, 0, buffer.Length);
 622    }
 623
 624    /// <summary>
 625    /// Inflates the compressed stream to the output buffer.  If this
 626    /// returns 0, you should check, whether needsDictionary(),
 627    /// needsInput() or finished() returns true, to determine why no
 628    /// further output is produced.
 629    /// </summary>
 630    /// <param name="buffer">
 631    /// the output buffer.
 632    /// </param>
 633    /// <param name="offset">
 634    /// the offset in buffer where storing starts.
 635    /// </param>
 636    /// <param name="count">
 637    /// the maximum number of bytes to output.
 638    /// </param>
 639    /// <returns>
 640    /// the number of bytes written to the buffer, 0 if no further output can be produced.
 641    /// </returns>
 642    /// <exception cref="System.ArgumentOutOfRangeException">
 643    /// if count is less than 0.
 644    /// </exception>
 645    /// <exception cref="System.ArgumentOutOfRangeException">
 646    /// if the index and / or count are wrong.
 647    /// </exception>
 648    /// <exception cref="System.FormatException">
 649    /// if deflated stream is invalid.
 650    /// </exception>
 651    public int Inflate(byte[] buffer, int offset, int count)
 652    {
 2212653       if (buffer == null) {
 0654        throw new ArgumentNullException(nameof(buffer));
 655      }
 656
 2212657       if (count < 0) {
 0658        throw new ArgumentOutOfRangeException(nameof(count), "count cannot be negative");
 659      }
 660
 2212661       if (offset < 0) {
 0662        throw new ArgumentOutOfRangeException(nameof(offset), "offset cannot be negative");
 663      }
 664
 2212665       if (offset + count > buffer.Length) {
 0666        throw new ArgumentException("count exceeds buffer bounds");
 667      }
 668
 669      // Special case: count may be zero
 2212670       if (count == 0) {
 20671         if (!IsFinished) { // -jr- 08-Nov-2003 INFLATE_BUG fix..
 20672          Decode();
 673        }
 20674        return 0;
 675      }
 676
 2192677      int bytesCopied = 0;
 678
 679      do {
 4524680         if (mode != DECODE_CHKSUM) {
 681          /* Don't give away any output, if we are waiting for the
 682          * checksum in the input stream.
 683          *
 684          * With this trick we have always:
 685          *   IsNeedingInput() and not IsFinished()
 686          *   implies more output can be produced.
 687          */
 4523688          int more = outputWindow.CopyOutput(buffer, offset, count);
 4523689           if (more > 0) {
 1679690            adler.Update(buffer, offset, more);
 1679691            offset += more;
 1679692            bytesCopied += more;
 1679693            totalOut += (long)more;
 1679694            count -= more;
 1679695             if (count == 0) {
 122696              return bytesCopied;
 697            }
 698          }
 699        }
 4402700       } while (Decode() || ((outputWindow.GetAvailable() > 0) && (mode != DECODE_CHKSUM)));
 2070701      return bytesCopied;
 702    }
 703
 704    /// <summary>
 705    /// Returns true, if the input buffer is empty.
 706    /// You should then call setInput().
 707    /// NOTE: This method also returns true when the stream is finished.
 708    /// </summary>
 709    public bool IsNeedingInput {
 710      get {
 1367711        return input.IsNeedingInput;
 712      }
 713    }
 714
 715    /// <summary>
 716    /// Returns true, if a preset dictionary is needed to inflate the input.
 717    /// </summary>
 718    public bool IsNeedingDictionary {
 719      get {
 845720        return mode == DECODE_DICT && neededBits == 0;
 721      }
 722    }
 723
 724    /// <summary>
 725    /// Returns true, if the inflater has finished.  This means, that no
 726    /// input is needed and no output can be produced.
 727    /// </summary>
 728    public bool IsFinished {
 729      get {
 2106730        return mode == FINISHED && outputWindow.GetAvailable() == 0;
 731      }
 732    }
 733
 734    /// <summary>
 735    /// Gets the adler checksum.  This is either the checksum of all
 736    /// uncompressed bytes returned by inflate(), or if needsDictionary()
 737    /// returns true (and thus no output was yet produced) this is the
 738    /// adler checksum of the expected dictionary.
 739    /// </summary>
 740    /// <returns>
 741    /// the adler checksum.
 742    /// </returns>
 743    public int Adler {
 744      get {
 0745        return IsNeedingDictionary ? readAdler : (int)adler.Value;
 746      }
 747    }
 748
 749    /// <summary>
 750    /// Gets the total number of output bytes returned by Inflate().
 751    /// </summary>
 752    /// <returns>
 753    /// the total number of output bytes.
 754    /// </returns>
 755    public long TotalOut {
 756      get {
 13757        return totalOut;
 758      }
 759    }
 760
 761    /// <summary>
 762    /// Gets the total number of processed compressed input bytes.
 763    /// </summary>
 764    /// <returns>
 765    /// The total number of bytes of processed input bytes.
 766    /// </returns>
 767    public long TotalIn {
 768      get {
 22769        return totalIn - (long)RemainingInput;
 770      }
 771    }
 772
 773    /// <summary>
 774    /// Gets the number of unprocessed input bytes.  Useful, if the end of the
 775    /// stream is reached and you want to further process the bytes after
 776    /// the deflate stream.
 777    /// </summary>
 778    /// <returns>
 779    /// The number of bytes of the input which have not been processed.
 780    /// </returns>
 781    public int RemainingInput {
 782      // TODO: This should be a long?
 783      get {
 47784        return input.AvailableBytes;
 785      }
 786    }
 787  }
 788}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_InflaterDynHeader.htm b/docs/opencover/ICSharpCode.SharpZipLib_InflaterDynHeader.htm new file mode 100644 index 000000000..5255f42ae --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_InflaterDynHeader.htm @@ -0,0 +1,215 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\InflaterDynHeader.cs
Covered lines:63
Uncovered lines:10
Coverable lines:73
Total lines:170
Line coverage:86.3%
Branch coverage:54.2%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
Decode(...)2184.1355.56
BuildLitLenTree()1100100
BuildDistTree()1100100
.cctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\InflaterDynHeader.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 3
 4namespace ICSharpCode.SharpZipLib.Zip.Compression
 5{
 6  class InflaterDynHeader
 7  {
 8    #region Constants
 9    const int LNUM = 0;
 10    const int DNUM = 1;
 11    const int BLNUM = 2;
 12    const int BLLENS = 3;
 13    const int LENS = 4;
 14    const int REPS = 5;
 15
 116    static readonly int[] repMin = { 3, 3, 11 };
 117    static readonly int[] repBits = { 2, 3, 7 };
 18
 119    static readonly int[] BL_ORDER =
 120    { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
 21    #endregion
 22
 23    public bool Decode(StreamManipulator input)
 24    {
 25      decode_loop:
 26      for (;;) {
 1027         switch (mode) {
 28          case LNUM:
 129            lnum = input.PeekBits(5);
 130             if (lnum < 0) {
 031              return false;
 32            }
 133            lnum += 257;
 134            input.DropBits(5);
 35            //        System.err.println("LNUM: "+lnum);
 136            mode = DNUM;
 37            goto case DNUM; // fall through
 38          case DNUM:
 139            dnum = input.PeekBits(5);
 140             if (dnum < 0) {
 041              return false;
 42            }
 143            dnum++;
 144            input.DropBits(5);
 45            //        System.err.println("DNUM: "+dnum);
 146            num = lnum + dnum;
 147            litdistLens = new byte[num];
 148            mode = BLNUM;
 49            goto case BLNUM; // fall through
 50          case BLNUM:
 151            blnum = input.PeekBits(4);
 152             if (blnum < 0) {
 053              return false;
 54            }
 155            blnum += 4;
 156            input.DropBits(4);
 157            blLens = new byte[19];
 158            ptr = 0;
 59            //        System.err.println("BLNUM: "+blnum);
 160            mode = BLLENS;
 161            goto case BLLENS; // fall through
 62          case BLLENS:
 1963             while (ptr < blnum) {
 1864              int len = input.PeekBits(3);
 1865               if (len < 0) {
 066                return false;
 67              }
 1868              input.DropBits(3);
 69              //      System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
 1870              blLens[BL_ORDER[ptr]] = (byte)len;
 1871              ptr++;
 72            }
 173            blTree = new InflaterHuffmanTree(blLens);
 174            blLens = null;
 175            ptr = 0;
 176            mode = LENS;
 177            goto case LENS; // fall through
 78          case LENS: {
 79              int symbol;
 4580               while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {
 81                /* Normal case: symbol in [0..15] */
 82
 83                //        System.err.println("litdistLens["+ptr+"]: "+symbol);
 3684                litdistLens[ptr++] = lastLen = (byte)symbol;
 85
 3686                 if (ptr == num) {
 87                  /* Finished */
 188                  return true;
 89                }
 90              }
 91
 92              /* need more input ? */
 993               if (symbol < 0) {
 094                return false;
 95              }
 96
 97              /* otherwise repeat code */
 998               if (symbol >= 17) {
 99                /* repeat zero */
 100                //        System.err.println("repeating zero");
 9101                lastLen = 0;
 9102              } else {
 0103                 if (ptr == 0) {
 0104                  throw new SharpZipBaseException();
 105                }
 106              }
 9107              repSymbol = symbol - 16;
 108            }
 9109            mode = REPS;
 110            goto case REPS; // fall through
 111          case REPS: {
 9112              int bits = repBits[repSymbol];
 9113              int count = input.PeekBits(bits);
 9114               if (count < 0) {
 0115                return false;
 116              }
 9117              input.DropBits(bits);
 9118              count += repMin[repSymbol];
 119              //          System.err.println("litdistLens repeated: "+count);
 120
 9121               if (ptr + count > num) {
 0122                throw new SharpZipBaseException();
 123              }
 239124               while (count-- > 0) {
 230125                litdistLens[ptr++] = lastLen;
 126              }
 127
 9128               if (ptr == num) {
 129                /* Finished */
 0130                return true;
 131              }
 132            }
 9133            mode = LENS;
 9134            goto decode_loop;
 135        }
 136      }
 137    }
 138
 139    public InflaterHuffmanTree BuildLitLenTree()
 140    {
 1141      byte[] litlenLens = new byte[lnum];
 1142      Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
 1143      return new InflaterHuffmanTree(litlenLens);
 144    }
 145
 146    public InflaterHuffmanTree BuildDistTree()
 147    {
 1148      byte[] distLens = new byte[dnum];
 1149      Array.Copy(litdistLens, lnum, distLens, 0, dnum);
 1150      return new InflaterHuffmanTree(distLens);
 151    }
 152
 153    #region Instance Fields
 154    byte[] blLens;
 155    byte[] litdistLens;
 156
 157    InflaterHuffmanTree blTree;
 158
 159    /// <summary>
 160    /// The current decode mode
 161    /// </summary>
 162    int mode;
 163    int lnum, dnum, blnum, num;
 164    int repSymbol;
 165    byte lastLen;
 166    int ptr;
 167    #endregion
 168
 169  }
 170}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_InflaterHuffmanTree.htm b/docs/opencover/ICSharpCode.SharpZipLib_InflaterHuffmanTree.htm new file mode 100644 index 000000000..9ce45e0ba --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_InflaterHuffmanTree.htm @@ -0,0 +1,238 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\InflaterHuffmanTree.cs
Covered lines:65
Uncovered lines:23
Coverable lines:88
Total lines:193
Line coverage:73.8%
Branch coverage:75%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.cctor()690100
.ctor(...)1100100
BuildTree(...)1282.6982.61
GetSymbol(...)741.6746.15
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\InflaterHuffmanTree.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 3
 4namespace ICSharpCode.SharpZipLib.Zip.Compression
 5{
 6  /// <summary>
 7  /// Huffman tree used for inflation
 8  /// </summary>
 9  public class InflaterHuffmanTree
 10  {
 11    #region Constants
 12    const int MAX_BITLEN = 15;
 13    #endregion
 14
 15    #region Instance Fields
 16    short[] tree;
 17    #endregion
 18
 19    /// <summary>
 20    /// Literal length tree
 21    /// </summary>
 22    public static InflaterHuffmanTree defLitLenTree;
 23
 24    /// <summary>
 25    /// Distance tree
 26    /// </summary>
 27    public static InflaterHuffmanTree defDistTree;
 28
 29    static InflaterHuffmanTree()
 30    {
 31      try {
 132        byte[] codeLengths = new byte[288];
 133        int i = 0;
 14534         while (i < 144) {
 14435          codeLengths[i++] = 8;
 36        }
 11337         while (i < 256) {
 11238          codeLengths[i++] = 9;
 39        }
 2540         while (i < 280) {
 2441          codeLengths[i++] = 7;
 42        }
 943         while (i < 288) {
 844          codeLengths[i++] = 8;
 45        }
 146        defLitLenTree = new InflaterHuffmanTree(codeLengths);
 47
 148        codeLengths = new byte[32];
 149        i = 0;
 3350         while (i < 32) {
 3251          codeLengths[i++] = 5;
 52        }
 153        defDistTree = new InflaterHuffmanTree(codeLengths);
 154      } catch (Exception) {
 055        throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal");
 56      }
 157    }
 58
 59    #region Constructors
 60    /// <summary>
 61    /// Constructs a Huffman tree from the array of code lengths.
 62    /// </summary>
 63    /// <param name = "codeLengths">
 64    /// the array of code lengths
 65    /// </param>
 566    public InflaterHuffmanTree(byte[] codeLengths)
 67    {
 568      BuildTree(codeLengths);
 569    }
 70    #endregion
 71
 72    void BuildTree(byte[] codeLengths)
 73    {
 574      int[] blCount = new int[MAX_BITLEN + 1];
 575      int[] nextCode = new int[MAX_BITLEN + 1];
 76
 122077       for (int i = 0; i < codeLengths.Length; i++) {
 60578        int bits = codeLengths[i];
 60579         if (bits > 0) {
 35880          blCount[bits]++;
 81        }
 82      }
 83
 584      int code = 0;
 585      int treeSize = 512;
 16086       for (int bits = 1; bits <= MAX_BITLEN; bits++) {
 7587        nextCode[bits] = code;
 7588        code += blCount[bits] << (16 - bits);
 7589         if (bits >= 10) {
 90          /* We need an extra table for bit lengths >= 10. */
 3091          int start = nextCode[bits] & 0x1ff80;
 3092          int end = code & 0x1ff80;
 3093          treeSize += (end - start) >> (16 - bits);
 94        }
 95      }
 96
 97      /* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
 98            if (code != 65536)
 99            {
 100              throw new SharpZipBaseException("Code lengths don't add up properly.");
 101            }
 102      */
 103      /* Now create and fill the extra tables from longest to shortest
 104      * bit len.  This way the sub trees will be aligned.
 105      */
 5106      tree = new short[treeSize];
 5107      int treePtr = 512;
 70108       for (int bits = MAX_BITLEN; bits >= 10; bits--) {
 30109        int end = code & 0x1ff80;
 30110        code -= blCount[bits] << (16 - bits);
 30111        int start = code & 0x1ff80;
 60112         for (int i = start; i < end; i += 1 << 7) {
 0113          tree[DeflaterHuffman.BitReverse(i)] = (short)((-treePtr << 4) | bits);
 0114          treePtr += 1 << (bits - 9);
 115        }
 116      }
 117
 1220118       for (int i = 0; i < codeLengths.Length; i++) {
 605119        int bits = codeLengths[i];
 605120         if (bits == 0) {
 121          continue;
 122        }
 358123        code = nextCode[bits];
 358124        int revcode = DeflaterHuffman.BitReverse(code);
 358125         if (bits <= 9) {
 126          do {
 2560127            tree[revcode] = (short)((i << 4) | bits);
 2560128            revcode += 1 << bits;
 2560129           } while (revcode < 512);
 358130        } else {
 0131          int subTree = tree[revcode & 511];
 0132          int treeLen = 1 << (subTree & 15);
 0133          subTree = -(subTree >> 4);
 134          do {
 0135            tree[subTree | (revcode >> 9)] = (short)((i << 4) | bits);
 0136            revcode += 1 << bits;
 0137           } while (revcode < treeLen);
 138        }
 358139        nextCode[bits] = code + (1 << (16 - bits));
 140      }
 141
 5142    }
 143
 144    /// <summary>
 145    /// Reads the next symbol from input.  The symbol is encoded using the
 146    /// huffman tree.
 147    /// </summary>
 148    /// <param name="input">
 149    /// input the input source.
 150    /// </param>
 151    /// <returns>
 152    /// the next symbol, or -1 if not enough input is available.
 153    /// </returns>
 154    public int GetSymbol(StreamManipulator input)
 155    {
 156      int lookahead, symbol;
 9839157       if ((lookahead = input.PeekBits(9)) >= 0) {
 9816158         if ((symbol = tree[lookahead]) >= 0) {
 9816159          input.DropBits(symbol & 15);
 9816160          return symbol >> 4;
 161        }
 0162        int subtree = -(symbol >> 4);
 0163        int bitlen = symbol & 15;
 0164         if ((lookahead = input.PeekBits(bitlen)) >= 0) {
 0165          symbol = tree[subtree | (lookahead >> 9)];
 0166          input.DropBits(symbol & 15);
 0167          return symbol >> 4;
 168        } else {
 0169          int bits = input.AvailableBits;
 0170          lookahead = input.PeekBits(bits);
 0171          symbol = tree[subtree | (lookahead >> 9)];
 0172           if ((symbol & 15) <= bits) {
 0173            input.DropBits(symbol & 15);
 0174            return symbol >> 4;
 175          } else {
 0176            return -1;
 177          }
 178        }
 179      } else {
 23180        int bits = input.AvailableBits;
 23181        lookahead = input.PeekBits(bits);
 23182        symbol = tree[lookahead];
 23183         if (symbol >= 0 && (symbol & 15) <= bits) {
 23184          input.DropBits(symbol & 15);
 23185          return symbol >> 4;
 186        } else {
 0187          return -1;
 188        }
 189      }
 190    }
 191  }
 192}
 193
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_InflaterInputBuffer.htm b/docs/opencover/ICSharpCode.SharpZipLib_InflaterInputBuffer.htm new file mode 100644 index 000000000..b5886cf83 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_InflaterInputBuffer.htm @@ -0,0 +1,714 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\InflaterInputStream.cs
Covered lines:72
Uncovered lines:14
Coverable lines:86
Total lines:662
Line coverage:83.7%
Branch coverage:71%
+

Metrics

+ + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor(...)285.7166.67
SetInflaterInput(...)210066.67
Fill()4100100
ReadRawBuffer(...)1100100
ReadRawBuffer(...)573.3355.56
ReadClearTextBuffer(...)586.6777.78
ReadLeByte()385.7180
ReadLeShort()1100100
ReadLeInt()1100100
ReadLeLong()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\InflaterInputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Security.Cryptography;
 4
 5namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
 6{
 7  /// <summary>
 8  /// An input buffer customised for use by <see cref="InflaterInputStream"/>
 9  /// </summary>
 10  /// <remarks>
 11  /// The buffer supports decryption of incoming data.
 12  /// </remarks>
 13  public class InflaterInputBuffer
 14  {
 15    #region Constructors
 16    /// <summary>
 17    /// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size
 18    /// </summary>
 19    /// <param name="stream">The stream to buffer.</param>
 020    public InflaterInputBuffer(Stream stream) : this(stream, 4096)
 21    {
 022    }
 23
 24    /// <summary>
 25    /// Initialise a new instance of <see cref="InflaterInputBuffer"/>
 26    /// </summary>
 27    /// <param name="stream">The stream to buffer.</param>
 28    /// <param name="bufferSize">The size to use for the buffer</param>
 29    /// <remarks>A minimum buffer size of 1KB is permitted.  Lower sizes are treated as 1KB.</remarks>
 43530    public InflaterInputBuffer(Stream stream, int bufferSize)
 31    {
 43532      inputStream = stream;
 43533       if (bufferSize < 1024) {
 034        bufferSize = 1024;
 35      }
 43536      rawData = new byte[bufferSize];
 43537      clearText = rawData;
 43538    }
 39    #endregion
 40
 41    /// <summary>
 42    /// Get the length of bytes bytes in the <see cref="RawData"/>
 43    /// </summary>
 44    public int RawLength {
 45      get {
 046        return rawLength;
 47      }
 48    }
 49
 50    /// <summary>
 51    /// Get the contents of the raw data buffer.
 52    /// </summary>
 53    /// <remarks>This may contain encrypted data.</remarks>
 54    public byte[] RawData {
 55      get {
 056        return rawData;
 57      }
 58    }
 59
 60    /// <summary>
 61    /// Get the number of useable bytes in <see cref="ClearText"/>
 62    /// </summary>
 63    public int ClearTextLength {
 64      get {
 065        return clearTextLength;
 66      }
 67    }
 68
 69    /// <summary>
 70    /// Get the contents of the clear text buffer.
 71    /// </summary>
 72    public byte[] ClearText {
 73      get {
 074        return clearText;
 75      }
 76    }
 77
 78    /// <summary>
 79    /// Get/set the number of bytes available
 80    /// </summary>
 81    public int Available {
 283782      get { return available; }
 7883      set { available = value; }
 84    }
 85
 86    /// <summary>
 87    /// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.
 88    /// </summary>
 89    /// <param name="inflater">The inflater to set input for.</param>
 90    public void SetInflaterInput(Inflater inflater)
 91    {
 143392       if (available > 0) {
 143393        inflater.SetInput(clearText, clearTextLength - available, available);
 143394        available = 0;
 95      }
 143396    }
 97
 98    /// <summary>
 99    /// Fill the buffer from the underlying input stream.
 100    /// </summary>
 101    public void Fill()
 102    {
 1448103      rawLength = 0;
 1448104      int toRead = rawData.Length;
 105
 2896106       while (toRead > 0) {
 1877107        int count = inputStream.Read(rawData, rawLength, toRead);
 1877108         if (count <= 0) {
 109          break;
 110        }
 1448111        rawLength += count;
 1448112        toRead -= count;
 113      }
 114
 1448115       if (cryptoTransform != null) {
 264116        clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0);
 264117      } else {
 1184118        clearTextLength = rawLength;
 119      }
 120
 1448121      available = clearTextLength;
 1448122    }
 123
 124    /// <summary>
 125    /// Read a buffer directly from the input stream
 126    /// </summary>
 127    /// <param name="buffer">The buffer to fill</param>
 128    /// <returns>Returns the number of bytes read.</returns>
 129    public int ReadRawBuffer(byte[] buffer)
 130    {
 159131      return ReadRawBuffer(buffer, 0, buffer.Length);
 132    }
 133
 134    /// <summary>
 135    /// Read a buffer directly from the input stream
 136    /// </summary>
 137    /// <param name="outBuffer">The buffer to read into</param>
 138    /// <param name="offset">The offset to start reading data into.</param>
 139    /// <param name="length">The number of bytes to read.</param>
 140    /// <returns>Returns the number of bytes read.</returns>
 141    public int ReadRawBuffer(byte[] outBuffer, int offset, int length)
 142    {
 159143       if (length < 0) {
 0144        throw new ArgumentOutOfRangeException(nameof(length));
 145      }
 146
 159147      int currentOffset = offset;
 159148      int currentLength = length;
 149
 318150       while (currentLength > 0) {
 159151         if (available <= 0) {
 0152          Fill();
 0153           if (available <= 0) {
 0154            return 0;
 155          }
 156        }
 159157        int toCopy = Math.Min(currentLength, available);
 159158        System.Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy);
 159159        currentOffset += toCopy;
 159160        currentLength -= toCopy;
 159161        available -= toCopy;
 162      }
 159163      return length;
 164    }
 165
 166    /// <summary>
 167    /// Read clear text data from the input stream.
 168    /// </summary>
 169    /// <param name="outBuffer">The buffer to add data to.</param>
 170    /// <param name="offset">The offset to start adding data at.</param>
 171    /// <param name="length">The number of bytes to read.</param>
 172    /// <returns>Returns the number of bytes actually read.</returns>
 173    public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)
 174    {
 27175       if (length < 0) {
 0176        throw new ArgumentOutOfRangeException(nameof(length));
 177      }
 178
 27179      int currentOffset = offset;
 27180      int currentLength = length;
 181
 78182       while (currentLength > 0) {
 51183         if (available <= 0) {
 24184          Fill();
 24185           if (available <= 0) {
 0186            return 0;
 187          }
 188        }
 189
 51190        int toCopy = Math.Min(currentLength, available);
 51191        Array.Copy(clearText, clearTextLength - (int)available, outBuffer, currentOffset, toCopy);
 51192        currentOffset += toCopy;
 51193        currentLength -= toCopy;
 51194        available -= toCopy;
 195      }
 27196      return length;
 197    }
 198
 199    /// <summary>
 200    /// Read a <see cref="byte"/> from the input stream.
 201    /// </summary>
 202    /// <returns>Returns the byte read.</returns>
 203    public int ReadLeByte()
 204    {
 2574205       if (available <= 0) {
 57206        Fill();
 57207         if (available <= 0) {
 0208          throw new ZipException("EOF in header");
 209        }
 210      }
 2574211      byte result = rawData[rawLength - available];
 2574212      available -= 1;
 2574213      return result;
 214    }
 215
 216    /// <summary>
 217    /// Read an <see cref="short"/> in little endian byte order.
 218    /// </summary>
 219    /// <returns>The short value read case to an int.</returns>
 220    public int ReadLeShort()
 221    {
 1287222      return ReadLeByte() | (ReadLeByte() << 8);
 223    }
 224
 225    /// <summary>
 226    /// Read an <see cref="int"/> in little endian byte order.
 227    /// </summary>
 228    /// <returns>The int value read.</returns>
 229    public int ReadLeInt()
 230    {
 441231      return ReadLeShort() | (ReadLeShort() << 16);
 232    }
 233
 234    /// <summary>
 235    /// Read a <see cref="long"/> in little endian byte order.
 236    /// </summary>
 237    /// <returns>The long value read.</returns>
 238    public long ReadLeLong()
 239    {
 10240      return (uint)ReadLeInt() | ((long)ReadLeInt() << 32);
 241    }
 242
 243    /// <summary>
 244    /// Get/set the <see cref="ICryptoTransform"/> to apply to any data.
 245    /// </summary>
 246    /// <remarks>Set this value to null to have no transform applied.</remarks>
 247    public ICryptoTransform CryptoTransform {
 248      set {
 102249        cryptoTransform = value;
 102250         if (cryptoTransform != null) {
 24251           if (rawData == clearText) {
 24252             if (internalClearText == null) {
 23253              internalClearText = new byte[rawData.Length];
 254            }
 24255            clearText = internalClearText;
 256          }
 24257          clearTextLength = rawLength;
 24258           if (available > 0) {
 24259            cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available);
 260          }
 24261        } else {
 78262          clearText = rawData;
 78263          clearTextLength = rawLength;
 264        }
 78265      }
 266    }
 267
 268    #region Instance Fields
 269    int rawLength;
 270    byte[] rawData;
 271
 272    int clearTextLength;
 273    byte[] clearText;
 274    byte[] internalClearText;
 275
 276    int available;
 277
 278    ICryptoTransform cryptoTransform;
 279    Stream inputStream;
 280    #endregion
 281  }
 282
 283  /// <summary>
 284  /// This filter stream is used to decompress data compressed using the "deflate"
 285  /// format. The "deflate" format is described in RFC 1951.
 286  ///
 287  /// This stream may form the basis for other decompression filters, such
 288  /// as the <see cref="ICSharpCode.SharpZipLib.GZip.GZipInputStream">GZipInputStream</see>.
 289  ///
 290  /// Author of the original java version : John Leuner.
 291  /// </summary>
 292  public class InflaterInputStream : Stream
 293  {
 294    #region Constructors
 295    /// <summary>
 296    /// Create an InflaterInputStream with the default decompressor
 297    /// and a default buffer size of 4KB.
 298    /// </summary>
 299    /// <param name = "baseInputStream">
 300    /// The InputStream to read bytes from
 301    /// </param>
 302    public InflaterInputStream(Stream baseInputStream)
 303      : this(baseInputStream, new Inflater(), 4096)
 304    {
 305    }
 306
 307    /// <summary>
 308    /// Create an InflaterInputStream with the specified decompressor
 309    /// and a default buffer size of 4KB.
 310    /// </summary>
 311    /// <param name = "baseInputStream">
 312    /// The source of input data
 313    /// </param>
 314    /// <param name = "inf">
 315    /// The decompressor used to decompress data read from baseInputStream
 316    /// </param>
 317    public InflaterInputStream(Stream baseInputStream, Inflater inf)
 318      : this(baseInputStream, inf, 4096)
 319    {
 320    }
 321
 322    /// <summary>
 323    /// Create an InflaterInputStream with the specified decompressor
 324    /// and the specified buffer size.
 325    /// </summary>
 326    /// <param name = "baseInputStream">
 327    /// The InputStream to read bytes from
 328    /// </param>
 329    /// <param name = "inflater">
 330    /// The decompressor to use
 331    /// </param>
 332    /// <param name = "bufferSize">
 333    /// Size of the buffer to use
 334    /// </param>
 335    public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)
 336    {
 337      if (baseInputStream == null) {
 338        throw new ArgumentNullException(nameof(baseInputStream));
 339      }
 340
 341      if (inflater == null) {
 342        throw new ArgumentNullException(nameof(inflater));
 343      }
 344
 345      if (bufferSize <= 0) {
 346        throw new ArgumentOutOfRangeException(nameof(bufferSize));
 347      }
 348
 349      this.baseInputStream = baseInputStream;
 350      this.inf = inflater;
 351
 352      inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);
 353    }
 354
 355    #endregion
 356
 357    /// <summary>
 358    /// Get/set flag indicating ownership of underlying stream.
 359    /// When the flag is true <see cref="Close"/> will close the underlying stream also.
 360    /// </summary>
 361    /// <remarks>
 362    /// The default value is true.
 363    /// </remarks>
 364    public bool IsStreamOwner {
 365      get { return isStreamOwner; }
 366      set { isStreamOwner = value; }
 367    }
 368
 369    /// <summary>
 370    /// Skip specified number of bytes of uncompressed data
 371    /// </summary>
 372    /// <param name ="count">
 373    /// Number of bytes to skip
 374    /// </param>
 375    /// <returns>
 376    /// The number of bytes skipped, zero if the end of
 377    /// stream has been reached
 378    /// </returns>
 379    /// <exception cref="ArgumentOutOfRangeException">
 380    /// <paramref name="count">The number of bytes</paramref> to skip is less than or equal to zero.
 381    /// </exception>
 382    public long Skip(long count)
 383    {
 384      if (count <= 0) {
 385        throw new ArgumentOutOfRangeException(nameof(count));
 386      }
 387
 388      // v0.80 Skip by seeking if underlying stream supports it...
 389      if (baseInputStream.CanSeek) {
 390        baseInputStream.Seek(count, SeekOrigin.Current);
 391        return count;
 392      } else {
 393        int length = 2048;
 394        if (count < length) {
 395          length = (int)count;
 396        }
 397
 398        byte[] tmp = new byte[length];
 399        int readCount = 1;
 400        long toSkip = count;
 401
 402        while ((toSkip > 0) && (readCount > 0)) {
 403          if (toSkip < length) {
 404            length = (int)toSkip;
 405          }
 406
 407          readCount = baseInputStream.Read(tmp, 0, length);
 408          toSkip -= readCount;
 409        }
 410
 411        return count - toSkip;
 412      }
 413    }
 414
 415    /// <summary>
 416    /// Clear any cryptographic state.
 417    /// </summary>
 418    protected void StopDecrypting()
 419    {
 420      inputBuffer.CryptoTransform = null;
 421    }
 422
 423    /// <summary>
 424    /// Returns 0 once the end of the stream (EOF) has been reached.
 425    /// Otherwise returns 1.
 426    /// </summary>
 427    public virtual int Available {
 428      get {
 429        return inf.IsFinished ? 0 : 1;
 430      }
 431    }
 432
 433    /// <summary>
 434    /// Fills the buffer with more data to decompress.
 435    /// </summary>
 436    /// <exception cref="SharpZipBaseException">
 437    /// Stream ends early
 438    /// </exception>
 439    protected void Fill()
 440    {
 441      // Protect against redundant calls
 442      if (inputBuffer.Available <= 0) {
 443        inputBuffer.Fill();
 444        if (inputBuffer.Available <= 0) {
 445          throw new SharpZipBaseException("Unexpected EOF");
 446        }
 447      }
 448      inputBuffer.SetInflaterInput(inf);
 449    }
 450
 451    #region Stream Overrides
 452    /// <summary>
 453    /// Gets a value indicating whether the current stream supports reading
 454    /// </summary>
 455    public override bool CanRead {
 456      get {
 457        return baseInputStream.CanRead;
 458      }
 459    }
 460
 461    /// <summary>
 462    /// Gets a value of false indicating seeking is not supported for this stream.
 463    /// </summary>
 464    public override bool CanSeek {
 465      get {
 466        return false;
 467      }
 468    }
 469
 470    /// <summary>
 471    /// Gets a value of false indicating that this stream is not writeable.
 472    /// </summary>
 473    public override bool CanWrite {
 474      get {
 475        return false;
 476      }
 477    }
 478
 479    /// <summary>
 480    /// A value representing the length of the stream in bytes.
 481    /// </summary>
 482    public override long Length {
 483      get {
 484        return inputBuffer.RawLength;
 485      }
 486    }
 487
 488    /// <summary>
 489    /// The current position within the stream.
 490    /// Throws a NotSupportedException when attempting to set the position
 491    /// </summary>
 492    /// <exception cref="NotSupportedException">Attempting to set the position</exception>
 493    public override long Position {
 494      get {
 495        return baseInputStream.Position;
 496      }
 497      set {
 498        throw new NotSupportedException("InflaterInputStream Position not supported");
 499      }
 500    }
 501
 502    /// <summary>
 503    /// Flushes the baseInputStream
 504    /// </summary>
 505    public override void Flush()
 506    {
 507      baseInputStream.Flush();
 508    }
 509
 510    /// <summary>
 511    /// Sets the position within the current stream
 512    /// Always throws a NotSupportedException
 513    /// </summary>
 514    /// <param name="offset">The relative offset to seek to.</param>
 515    /// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>
 516    /// <returns>The new position in the stream.</returns>
 517    /// <exception cref="NotSupportedException">Any access</exception>
 518    public override long Seek(long offset, SeekOrigin origin)
 519    {
 520      throw new NotSupportedException("Seek not supported");
 521    }
 522
 523    /// <summary>
 524    /// Set the length of the current stream
 525    /// Always throws a NotSupportedException
 526    /// </summary>
 527    /// <param name="value">The new length value for the stream.</param>
 528    /// <exception cref="NotSupportedException">Any access</exception>
 529    public override void SetLength(long value)
 530    {
 531      throw new NotSupportedException("InflaterInputStream SetLength not supported");
 532    }
 533
 534    /// <summary>
 535    /// Writes a sequence of bytes to stream and advances the current position
 536    /// This method always throws a NotSupportedException
 537    /// </summary>
 538    /// <param name="buffer">Thew buffer containing data to write.</param>
 539    /// <param name="offset">The offset of the first byte to write.</param>
 540    /// <param name="count">The number of bytes to write.</param>
 541    /// <exception cref="NotSupportedException">Any access</exception>
 542    public override void Write(byte[] buffer, int offset, int count)
 543    {
 544      throw new NotSupportedException("InflaterInputStream Write not supported");
 545    }
 546
 547    /// <summary>
 548    /// Writes one byte to the current stream and advances the current position
 549    /// Always throws a NotSupportedException
 550    /// </summary>
 551    /// <param name="value">The byte to write.</param>
 552    /// <exception cref="NotSupportedException">Any access</exception>
 553    public override void WriteByte(byte value)
 554    {
 555      throw new NotSupportedException("InflaterInputStream WriteByte not supported");
 556    }
 557
 558    /// <summary>
 559    /// Entry point to begin an asynchronous write.  Always throws a NotSupportedException.
 560    /// </summary>
 561    /// <param name="buffer">The buffer to write data from</param>
 562    /// <param name="offset">Offset of first byte to write</param>
 563    /// <param name="count">The maximum number of bytes to write</param>
 564    /// <param name="callback">The method to be called when the asynchronous write operation is completed</param>
 565    /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from ot
 566    /// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>
 567    /// <exception cref="NotSupportedException">Any access</exception>
 568    public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
 569    {
 570      throw new NotSupportedException("InflaterInputStream BeginWrite not supported");
 571    }
 572
 573    /// <summary>
 574    /// Closes the input stream.  When <see cref="IsStreamOwner"></see>
 575    /// is true the underlying stream is also closed.
 576    /// </summary>
 577    public override void Close()
 578    {
 579      if (!isClosed) {
 580        isClosed = true;
 581        if (isStreamOwner) {
 582          baseInputStream.Close();
 583        }
 584      }
 585    }
 586
 587    /// <summary>
 588    /// Reads decompressed data into the provided buffer byte array
 589    /// </summary>
 590    /// <param name ="buffer">
 591    /// The array to read and decompress data into
 592    /// </param>
 593    /// <param name ="offset">
 594    /// The offset indicating where the data should be placed
 595    /// </param>
 596    /// <param name ="count">
 597    /// The number of bytes to decompress
 598    /// </param>
 599    /// <returns>The number of bytes read.  Zero signals the end of stream</returns>
 600    /// <exception cref="SharpZipBaseException">
 601    /// Inflater needs a dictionary
 602    /// </exception>
 603    public override int Read(byte[] buffer, int offset, int count)
 604    {
 605      if (inf.IsNeedingDictionary) {
 606        throw new SharpZipBaseException("Need a dictionary");
 607      }
 608
 609      int remainingBytes = count;
 610      while (true) {
 611        int bytesRead = inf.Inflate(buffer, offset, remainingBytes);
 612        offset += bytesRead;
 613        remainingBytes -= bytesRead;
 614
 615        if (remainingBytes == 0 || inf.IsFinished) {
 616          break;
 617        }
 618
 619        if (inf.IsNeedingInput) {
 620          Fill();
 621        } else if (bytesRead == 0) {
 622          throw new ZipException("Dont know what to do");
 623        }
 624      }
 625      return count - remainingBytes;
 626    }
 627    #endregion
 628
 629    #region Instance Fields
 630    /// <summary>
 631    /// Decompressor for this stream
 632    /// </summary>
 633    protected Inflater inf;
 634
 635    /// <summary>
 636    /// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.
 637    /// </summary>
 638    protected InflaterInputBuffer inputBuffer;
 639
 640    /// <summary>
 641    /// Base stream the inflater reads from.
 642    /// </summary>
 643    private Stream baseInputStream;
 644
 645    /// <summary>
 646    /// The compressed size
 647    /// </summary>
 648    protected long csize;
 649
 650    /// <summary>
 651    /// Flag indicating wether this instance has been closed or not.
 652    /// </summary>
 653    bool isClosed;
 654
 655    /// <summary>
 656    /// Flag indicating wether this instance is designated the stream owner.
 657    /// When closing if this flag is true the underlying stream is closed.
 658    /// </summary>
 659    bool isStreamOwner = true;
 660    #endregion
 661  }
 662}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_InflaterInputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_InflaterInputStream.htm new file mode 100644 index 000000000..6570d574b --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_InflaterInputStream.htm @@ -0,0 +1,717 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\InflaterInputStream.cs
Covered lines:38
Uncovered lines:36
Coverable lines:74
Total lines:662
Line coverage:51.3%
Branch coverage:39.4%
+

Metrics

+ + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)1100100
.ctor(...)47557.14
Skip(...)700
StopDecrypting()1100100
Fill()383.3360
Flush()100
Seek(...)100
SetLength(...)100
Write(...)100
WriteByte(...)100
BeginWrite(...)100
Close()3100100
Read(...)676.9263.64
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\InflaterInputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Security.Cryptography;
 4
 5namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
 6{
 7  /// <summary>
 8  /// An input buffer customised for use by <see cref="InflaterInputStream"/>
 9  /// </summary>
 10  /// <remarks>
 11  /// The buffer supports decryption of incoming data.
 12  /// </remarks>
 13  public class InflaterInputBuffer
 14  {
 15    #region Constructors
 16    /// <summary>
 17    /// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size
 18    /// </summary>
 19    /// <param name="stream">The stream to buffer.</param>
 20    public InflaterInputBuffer(Stream stream) : this(stream, 4096)
 21    {
 22    }
 23
 24    /// <summary>
 25    /// Initialise a new instance of <see cref="InflaterInputBuffer"/>
 26    /// </summary>
 27    /// <param name="stream">The stream to buffer.</param>
 28    /// <param name="bufferSize">The size to use for the buffer</param>
 29    /// <remarks>A minimum buffer size of 1KB is permitted.  Lower sizes are treated as 1KB.</remarks>
 30    public InflaterInputBuffer(Stream stream, int bufferSize)
 31    {
 32      inputStream = stream;
 33      if (bufferSize < 1024) {
 34        bufferSize = 1024;
 35      }
 36      rawData = new byte[bufferSize];
 37      clearText = rawData;
 38    }
 39    #endregion
 40
 41    /// <summary>
 42    /// Get the length of bytes bytes in the <see cref="RawData"/>
 43    /// </summary>
 44    public int RawLength {
 45      get {
 46        return rawLength;
 47      }
 48    }
 49
 50    /// <summary>
 51    /// Get the contents of the raw data buffer.
 52    /// </summary>
 53    /// <remarks>This may contain encrypted data.</remarks>
 54    public byte[] RawData {
 55      get {
 56        return rawData;
 57      }
 58    }
 59
 60    /// <summary>
 61    /// Get the number of useable bytes in <see cref="ClearText"/>
 62    /// </summary>
 63    public int ClearTextLength {
 64      get {
 65        return clearTextLength;
 66      }
 67    }
 68
 69    /// <summary>
 70    /// Get the contents of the clear text buffer.
 71    /// </summary>
 72    public byte[] ClearText {
 73      get {
 74        return clearText;
 75      }
 76    }
 77
 78    /// <summary>
 79    /// Get/set the number of bytes available
 80    /// </summary>
 81    public int Available {
 82      get { return available; }
 83      set { available = value; }
 84    }
 85
 86    /// <summary>
 87    /// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.
 88    /// </summary>
 89    /// <param name="inflater">The inflater to set input for.</param>
 90    public void SetInflaterInput(Inflater inflater)
 91    {
 92      if (available > 0) {
 93        inflater.SetInput(clearText, clearTextLength - available, available);
 94        available = 0;
 95      }
 96    }
 97
 98    /// <summary>
 99    /// Fill the buffer from the underlying input stream.
 100    /// </summary>
 101    public void Fill()
 102    {
 103      rawLength = 0;
 104      int toRead = rawData.Length;
 105
 106      while (toRead > 0) {
 107        int count = inputStream.Read(rawData, rawLength, toRead);
 108        if (count <= 0) {
 109          break;
 110        }
 111        rawLength += count;
 112        toRead -= count;
 113      }
 114
 115      if (cryptoTransform != null) {
 116        clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0);
 117      } else {
 118        clearTextLength = rawLength;
 119      }
 120
 121      available = clearTextLength;
 122    }
 123
 124    /// <summary>
 125    /// Read a buffer directly from the input stream
 126    /// </summary>
 127    /// <param name="buffer">The buffer to fill</param>
 128    /// <returns>Returns the number of bytes read.</returns>
 129    public int ReadRawBuffer(byte[] buffer)
 130    {
 131      return ReadRawBuffer(buffer, 0, buffer.Length);
 132    }
 133
 134    /// <summary>
 135    /// Read a buffer directly from the input stream
 136    /// </summary>
 137    /// <param name="outBuffer">The buffer to read into</param>
 138    /// <param name="offset">The offset to start reading data into.</param>
 139    /// <param name="length">The number of bytes to read.</param>
 140    /// <returns>Returns the number of bytes read.</returns>
 141    public int ReadRawBuffer(byte[] outBuffer, int offset, int length)
 142    {
 143      if (length < 0) {
 144        throw new ArgumentOutOfRangeException(nameof(length));
 145      }
 146
 147      int currentOffset = offset;
 148      int currentLength = length;
 149
 150      while (currentLength > 0) {
 151        if (available <= 0) {
 152          Fill();
 153          if (available <= 0) {
 154            return 0;
 155          }
 156        }
 157        int toCopy = Math.Min(currentLength, available);
 158        System.Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy);
 159        currentOffset += toCopy;
 160        currentLength -= toCopy;
 161        available -= toCopy;
 162      }
 163      return length;
 164    }
 165
 166    /// <summary>
 167    /// Read clear text data from the input stream.
 168    /// </summary>
 169    /// <param name="outBuffer">The buffer to add data to.</param>
 170    /// <param name="offset">The offset to start adding data at.</param>
 171    /// <param name="length">The number of bytes to read.</param>
 172    /// <returns>Returns the number of bytes actually read.</returns>
 173    public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)
 174    {
 175      if (length < 0) {
 176        throw new ArgumentOutOfRangeException(nameof(length));
 177      }
 178
 179      int currentOffset = offset;
 180      int currentLength = length;
 181
 182      while (currentLength > 0) {
 183        if (available <= 0) {
 184          Fill();
 185          if (available <= 0) {
 186            return 0;
 187          }
 188        }
 189
 190        int toCopy = Math.Min(currentLength, available);
 191        Array.Copy(clearText, clearTextLength - (int)available, outBuffer, currentOffset, toCopy);
 192        currentOffset += toCopy;
 193        currentLength -= toCopy;
 194        available -= toCopy;
 195      }
 196      return length;
 197    }
 198
 199    /// <summary>
 200    /// Read a <see cref="byte"/> from the input stream.
 201    /// </summary>
 202    /// <returns>Returns the byte read.</returns>
 203    public int ReadLeByte()
 204    {
 205      if (available <= 0) {
 206        Fill();
 207        if (available <= 0) {
 208          throw new ZipException("EOF in header");
 209        }
 210      }
 211      byte result = rawData[rawLength - available];
 212      available -= 1;
 213      return result;
 214    }
 215
 216    /// <summary>
 217    /// Read an <see cref="short"/> in little endian byte order.
 218    /// </summary>
 219    /// <returns>The short value read case to an int.</returns>
 220    public int ReadLeShort()
 221    {
 222      return ReadLeByte() | (ReadLeByte() << 8);
 223    }
 224
 225    /// <summary>
 226    /// Read an <see cref="int"/> in little endian byte order.
 227    /// </summary>
 228    /// <returns>The int value read.</returns>
 229    public int ReadLeInt()
 230    {
 231      return ReadLeShort() | (ReadLeShort() << 16);
 232    }
 233
 234    /// <summary>
 235    /// Read a <see cref="long"/> in little endian byte order.
 236    /// </summary>
 237    /// <returns>The long value read.</returns>
 238    public long ReadLeLong()
 239    {
 240      return (uint)ReadLeInt() | ((long)ReadLeInt() << 32);
 241    }
 242
 243    /// <summary>
 244    /// Get/set the <see cref="ICryptoTransform"/> to apply to any data.
 245    /// </summary>
 246    /// <remarks>Set this value to null to have no transform applied.</remarks>
 247    public ICryptoTransform CryptoTransform {
 248      set {
 249        cryptoTransform = value;
 250        if (cryptoTransform != null) {
 251          if (rawData == clearText) {
 252            if (internalClearText == null) {
 253              internalClearText = new byte[rawData.Length];
 254            }
 255            clearText = internalClearText;
 256          }
 257          clearTextLength = rawLength;
 258          if (available > 0) {
 259            cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available);
 260          }
 261        } else {
 262          clearText = rawData;
 263          clearTextLength = rawLength;
 264        }
 265      }
 266    }
 267
 268    #region Instance Fields
 269    int rawLength;
 270    byte[] rawData;
 271
 272    int clearTextLength;
 273    byte[] clearText;
 274    byte[] internalClearText;
 275
 276    int available;
 277
 278    ICryptoTransform cryptoTransform;
 279    Stream inputStream;
 280    #endregion
 281  }
 282
 283  /// <summary>
 284  /// This filter stream is used to decompress data compressed using the "deflate"
 285  /// format. The "deflate" format is described in RFC 1951.
 286  ///
 287  /// This stream may form the basis for other decompression filters, such
 288  /// as the <see cref="ICSharpCode.SharpZipLib.GZip.GZipInputStream">GZipInputStream</see>.
 289  ///
 290  /// Author of the original java version : John Leuner.
 291  /// </summary>
 292  public class InflaterInputStream : Stream
 293  {
 294    #region Constructors
 295    /// <summary>
 296    /// Create an InflaterInputStream with the default decompressor
 297    /// and a default buffer size of 4KB.
 298    /// </summary>
 299    /// <param name = "baseInputStream">
 300    /// The InputStream to read bytes from
 301    /// </param>
 302    public InflaterInputStream(Stream baseInputStream)
 3303      : this(baseInputStream, new Inflater(), 4096)
 304    {
 3305    }
 306
 307    /// <summary>
 308    /// Create an InflaterInputStream with the specified decompressor
 309    /// and a default buffer size of 4KB.
 310    /// </summary>
 311    /// <param name = "baseInputStream">
 312    /// The source of input data
 313    /// </param>
 314    /// <param name = "inf">
 315    /// The decompressor used to decompress data read from baseInputStream
 316    /// </param>
 317    public InflaterInputStream(Stream baseInputStream, Inflater inf)
 430318      : this(baseInputStream, inf, 4096)
 319    {
 430320    }
 321
 322    /// <summary>
 323    /// Create an InflaterInputStream with the specified decompressor
 324    /// and the specified buffer size.
 325    /// </summary>
 326    /// <param name = "baseInputStream">
 327    /// The InputStream to read bytes from
 328    /// </param>
 329    /// <param name = "inflater">
 330    /// The decompressor to use
 331    /// </param>
 332    /// <param name = "bufferSize">
 333    /// Size of the buffer to use
 334    /// </param>
 435335    public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)
 336    {
 435337       if (baseInputStream == null) {
 0338        throw new ArgumentNullException(nameof(baseInputStream));
 339      }
 340
 435341       if (inflater == null) {
 0342        throw new ArgumentNullException(nameof(inflater));
 343      }
 344
 435345       if (bufferSize <= 0) {
 0346        throw new ArgumentOutOfRangeException(nameof(bufferSize));
 347      }
 348
 435349      this.baseInputStream = baseInputStream;
 435350      this.inf = inflater;
 351
 435352      inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);
 435353    }
 354
 355    #endregion
 356
 357    /// <summary>
 358    /// Get/set flag indicating ownership of underlying stream.
 359    /// When the flag is true <see cref="Close"/> will close the underlying stream also.
 360    /// </summary>
 361    /// <remarks>
 362    /// The default value is true.
 363    /// </remarks>
 364    public bool IsStreamOwner {
 0365      get { return isStreamOwner; }
 4366      set { isStreamOwner = value; }
 367    }
 368
 369    /// <summary>
 370    /// Skip specified number of bytes of uncompressed data
 371    /// </summary>
 372    /// <param name ="count">
 373    /// Number of bytes to skip
 374    /// </param>
 375    /// <returns>
 376    /// The number of bytes skipped, zero if the end of
 377    /// stream has been reached
 378    /// </returns>
 379    /// <exception cref="ArgumentOutOfRangeException">
 380    /// <paramref name="count">The number of bytes</paramref> to skip is less than or equal to zero.
 381    /// </exception>
 382    public long Skip(long count)
 383    {
 0384       if (count <= 0) {
 0385        throw new ArgumentOutOfRangeException(nameof(count));
 386      }
 387
 388      // v0.80 Skip by seeking if underlying stream supports it...
 0389       if (baseInputStream.CanSeek) {
 0390        baseInputStream.Seek(count, SeekOrigin.Current);
 0391        return count;
 392      } else {
 0393        int length = 2048;
 0394         if (count < length) {
 0395          length = (int)count;
 396        }
 397
 0398        byte[] tmp = new byte[length];
 0399        int readCount = 1;
 0400        long toSkip = count;
 401
 0402         while ((toSkip > 0) && (readCount > 0)) {
 0403           if (toSkip < length) {
 0404            length = (int)toSkip;
 405          }
 406
 0407          readCount = baseInputStream.Read(tmp, 0, length);
 0408          toSkip -= readCount;
 409        }
 410
 0411        return count - toSkip;
 412      }
 413    }
 414
 415    /// <summary>
 416    /// Clear any cryptographic state.
 417    /// </summary>
 418    protected void StopDecrypting()
 419    {
 32420      inputBuffer.CryptoTransform = null;
 32421    }
 422
 423    /// <summary>
 424    /// Returns 0 once the end of the stream (EOF) has been reached.
 425    /// Otherwise returns 1.
 426    /// </summary>
 427    public virtual int Available {
 428      get {
 0429         return inf.IsFinished ? 0 : 1;
 430      }
 431    }
 432
 433    /// <summary>
 434    /// Fills the buffer with more data to decompress.
 435    /// </summary>
 436    /// <exception cref="SharpZipBaseException">
 437    /// Stream ends early
 438    /// </exception>
 439    protected void Fill()
 440    {
 441      // Protect against redundant calls
 1367442       if (inputBuffer.Available <= 0) {
 1367443        inputBuffer.Fill();
 1367444         if (inputBuffer.Available <= 0) {
 0445          throw new SharpZipBaseException("Unexpected EOF");
 446        }
 447      }
 1367448      inputBuffer.SetInflaterInput(inf);
 1367449    }
 450
 451    #region Stream Overrides
 452    /// <summary>
 453    /// Gets a value indicating whether the current stream supports reading
 454    /// </summary>
 455    public override bool CanRead {
 456      get {
 8457        return baseInputStream.CanRead;
 458      }
 459    }
 460
 461    /// <summary>
 462    /// Gets a value of false indicating seeking is not supported for this stream.
 463    /// </summary>
 464    public override bool CanSeek {
 465      get {
 2466        return false;
 467      }
 468    }
 469
 470    /// <summary>
 471    /// Gets a value of false indicating that this stream is not writeable.
 472    /// </summary>
 473    public override bool CanWrite {
 474      get {
 0475        return false;
 476      }
 477    }
 478
 479    /// <summary>
 480    /// A value representing the length of the stream in bytes.
 481    /// </summary>
 482    public override long Length {
 483      get {
 0484        return inputBuffer.RawLength;
 485      }
 486    }
 487
 488    /// <summary>
 489    /// The current position within the stream.
 490    /// Throws a NotSupportedException when attempting to set the position
 491    /// </summary>
 492    /// <exception cref="NotSupportedException">Attempting to set the position</exception>
 493    public override long Position {
 494      get {
 0495        return baseInputStream.Position;
 496      }
 497      set {
 0498        throw new NotSupportedException("InflaterInputStream Position not supported");
 499      }
 500    }
 501
 502    /// <summary>
 503    /// Flushes the baseInputStream
 504    /// </summary>
 505    public override void Flush()
 506    {
 0507      baseInputStream.Flush();
 0508    }
 509
 510    /// <summary>
 511    /// Sets the position within the current stream
 512    /// Always throws a NotSupportedException
 513    /// </summary>
 514    /// <param name="offset">The relative offset to seek to.</param>
 515    /// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>
 516    /// <returns>The new position in the stream.</returns>
 517    /// <exception cref="NotSupportedException">Any access</exception>
 518    public override long Seek(long offset, SeekOrigin origin)
 519    {
 0520      throw new NotSupportedException("Seek not supported");
 521    }
 522
 523    /// <summary>
 524    /// Set the length of the current stream
 525    /// Always throws a NotSupportedException
 526    /// </summary>
 527    /// <param name="value">The new length value for the stream.</param>
 528    /// <exception cref="NotSupportedException">Any access</exception>
 529    public override void SetLength(long value)
 530    {
 0531      throw new NotSupportedException("InflaterInputStream SetLength not supported");
 532    }
 533
 534    /// <summary>
 535    /// Writes a sequence of bytes to stream and advances the current position
 536    /// This method always throws a NotSupportedException
 537    /// </summary>
 538    /// <param name="buffer">Thew buffer containing data to write.</param>
 539    /// <param name="offset">The offset of the first byte to write.</param>
 540    /// <param name="count">The number of bytes to write.</param>
 541    /// <exception cref="NotSupportedException">Any access</exception>
 542    public override void Write(byte[] buffer, int offset, int count)
 543    {
 0544      throw new NotSupportedException("InflaterInputStream Write not supported");
 545    }
 546
 547    /// <summary>
 548    /// Writes one byte to the current stream and advances the current position
 549    /// Always throws a NotSupportedException
 550    /// </summary>
 551    /// <param name="value">The byte to write.</param>
 552    /// <exception cref="NotSupportedException">Any access</exception>
 553    public override void WriteByte(byte value)
 554    {
 0555      throw new NotSupportedException("InflaterInputStream WriteByte not supported");
 556    }
 557
 558    /// <summary>
 559    /// Entry point to begin an asynchronous write.  Always throws a NotSupportedException.
 560    /// </summary>
 561    /// <param name="buffer">The buffer to write data from</param>
 562    /// <param name="offset">Offset of first byte to write</param>
 563    /// <param name="count">The maximum number of bytes to write</param>
 564    /// <param name="callback">The method to be called when the asynchronous write operation is completed</param>
 565    /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from ot
 566    /// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>
 567    /// <exception cref="NotSupportedException">Any access</exception>
 568    public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
 569    {
 0570      throw new NotSupportedException("InflaterInputStream BeginWrite not supported");
 571    }
 572
 573    /// <summary>
 574    /// Closes the input stream.  When <see cref="IsStreamOwner"></see>
 575    /// is true the underlying stream is also closed.
 576    /// </summary>
 577    public override void Close()
 578    {
 392579       if (!isClosed) {
 383580        isClosed = true;
 383581         if (isStreamOwner) {
 381582          baseInputStream.Close();
 583        }
 584      }
 392585    }
 586
 587    /// <summary>
 588    /// Reads decompressed data into the provided buffer byte array
 589    /// </summary>
 590    /// <param name ="buffer">
 591    /// The array to read and decompress data into
 592    /// </param>
 593    /// <param name ="offset">
 594    /// The offset indicating where the data should be placed
 595    /// </param>
 596    /// <param name ="count">
 597    /// The number of bytes to decompress
 598    /// </param>
 599    /// <returns>The number of bytes read.  Zero signals the end of stream</returns>
 600    /// <exception cref="SharpZipBaseException">
 601    /// Inflater needs a dictionary
 602    /// </exception>
 603    public override int Read(byte[] buffer, int offset, int count)
 604    {
 845605       if (inf.IsNeedingDictionary) {
 0606        throw new SharpZipBaseException("Need a dictionary");
 607      }
 608
 845609      int remainingBytes = count;
 610      while (true) {
 2212611        int bytesRead = inf.Inflate(buffer, offset, remainingBytes);
 2212612        offset += bytesRead;
 2212613        remainingBytes -= bytesRead;
 614
 2212615         if (remainingBytes == 0 || inf.IsFinished) {
 616          break;
 617        }
 618
 1367619         if (inf.IsNeedingInput) {
 1367620          Fill();
 1367621         } else if (bytesRead == 0) {
 0622          throw new ZipException("Dont know what to do");
 623        }
 624      }
 845625      return count - remainingBytes;
 626    }
 627    #endregion
 628
 629    #region Instance Fields
 630    /// <summary>
 631    /// Decompressor for this stream
 632    /// </summary>
 633    protected Inflater inf;
 634
 635    /// <summary>
 636    /// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.
 637    /// </summary>
 638    protected InflaterInputBuffer inputBuffer;
 639
 640    /// <summary>
 641    /// Base stream the inflater reads from.
 642    /// </summary>
 643    private Stream baseInputStream;
 644
 645    /// <summary>
 646    /// The compressed size
 647    /// </summary>
 648    protected long csize;
 649
 650    /// <summary>
 651    /// Flag indicating wether this instance has been closed or not.
 652    /// </summary>
 653    bool isClosed;
 654
 655    /// <summary>
 656    /// Flag indicating wether this instance is designated the stream owner.
 657    /// When closing if this flag is true the underlying stream is closed.
 658    /// </summary>
 435659    bool isStreamOwner = true;
 660    #endregion
 661  }
 662}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_InvalidHeaderException.htm b/docs/opencover/ICSharpCode.SharpZipLib_InvalidHeaderException.htm new file mode 100644 index 000000000..6ff28f669 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_InvalidHeaderException.htm @@ -0,0 +1,95 @@ + + + + +ICSharpCode.SharpZipLib.Tar.InvalidHeaderException - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Tar.InvalidHeaderException
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\InvalidHeaderException.cs
Covered lines:0
Uncovered lines:8
Coverable lines:8
Total lines:51
Line coverage:0%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor()100
.ctor(...)100
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\InvalidHeaderException.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Runtime.Serialization;
 3
 4namespace ICSharpCode.SharpZipLib.Tar
 5{
 6  /// <summary>
 7  /// This exception is used to indicate that there is a problem
 8  /// with a TAR archive header.
 9  /// </summary>
 10  [Serializable]
 11  public class InvalidHeaderException : TarException
 12  {
 13
 14    /// <summary>
 15    /// Deserialization constructor
 16    /// </summary>
 17    /// <param name="information"><see cref="SerializationInfo"/> for this constructor</param>
 18    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
 19    protected InvalidHeaderException(SerializationInfo information, StreamingContext context)
 020      : base(information, context)
 21
 22    {
 023    }
 24
 25    /// <summary>
 26    /// Initialise a new instance of the InvalidHeaderException class.
 27    /// </summary>
 028    public InvalidHeaderException()
 29    {
 030    }
 31
 32    /// <summary>
 33    /// Initialises a new instance of the InvalidHeaderException class with a specified message.
 34    /// </summary>
 35    /// <param name="message">Message describing the exception cause.</param>
 36    public InvalidHeaderException(string message)
 037      : base(message)
 38    {
 039    }
 40
 41    /// <summary>
 42    /// Initialise a new instance of InvalidHeaderException
 43    /// </summary>
 44    /// <param name="message">Message describing the problem.</param>
 45    /// <param name="exception">The exception that is the cause of the current exception.</param>
 46    public InvalidHeaderException(string message, Exception exception)
 047      : base(message, exception)
 48    {
 049    }
 50  }
 51}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_KeysRequiredEventArgs.htm b/docs/opencover/ICSharpCode.SharpZipLib_KeysRequiredEventArgs.htm new file mode 100644 index 000000000..89a27dd01 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_KeysRequiredEventArgs.htm @@ -0,0 +1,4305 @@ + + + + +ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs
Covered lines:0
Uncovered lines:10
Coverable lines:10
Total lines:4263
Line coverage:0%
+

Metrics

+ + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.IO;
 4using System.Text;
 5using System.Globalization;
 6using System.Security.Cryptography;
 7using ICSharpCode.SharpZipLib.Encryption;
 8using ICSharpCode.SharpZipLib.Core;
 9using ICSharpCode.SharpZipLib.Checksum;
 10using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 11using ICSharpCode.SharpZipLib.Zip.Compression;
 12
 13namespace ICSharpCode.SharpZipLib.Zip
 14{
 15  #region Keys Required Event Args
 16  /// <summary>
 17  /// Arguments used with KeysRequiredEvent
 18  /// </summary>
 19  public class KeysRequiredEventArgs : EventArgs
 20  {
 21    #region Constructors
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 24    /// </summary>
 25    /// <param name="name">The name of the file for which keys are required.</param>
 026    public KeysRequiredEventArgs(string name)
 27    {
 028      fileName = name;
 029    }
 30
 31    /// <summary>
 32    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 33    /// </summary>
 34    /// <param name="name">The name of the file for which keys are required.</param>
 35    /// <param name="keyValue">The current key value.</param>
 036    public KeysRequiredEventArgs(string name, byte[] keyValue)
 37    {
 038      fileName = name;
 039      key = keyValue;
 040    }
 41
 42    #endregion
 43    #region Properties
 44    /// <summary>
 45    /// Gets the name of the file for which keys are required.
 46    /// </summary>
 47    public string FileName {
 048      get { return fileName; }
 49    }
 50
 51    /// <summary>
 52    /// Gets or sets the key value
 53    /// </summary>
 54    public byte[] Key {
 055      get { return key; }
 056      set { key = value; }
 57    }
 58    #endregion
 59
 60    #region Instance Fields
 61    string fileName;
 62    byte[] key;
 63    #endregion
 64  }
 65  #endregion
 66
 67  #region Test Definitions
 68  /// <summary>
 69  /// The strategy to apply to testing.
 70  /// </summary>
 71  public enum TestStrategy
 72  {
 73    /// <summary>
 74    /// Find the first error only.
 75    /// </summary>
 76    FindFirstError,
 77    /// <summary>
 78    /// Find all possible errors.
 79    /// </summary>
 80    FindAllErrors,
 81  }
 82
 83  /// <summary>
 84  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.
 85  /// </summary>
 86  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 87  public enum TestOperation
 88  {
 89    /// <summary>
 90    /// Setting up testing.
 91    /// </summary>
 92    Initialising,
 93
 94    /// <summary>
 95    /// Testing an individual entries header
 96    /// </summary>
 97    EntryHeader,
 98
 99    /// <summary>
 100    /// Testing an individual entries data
 101    /// </summary>
 102    EntryData,
 103
 104    /// <summary>
 105    /// Testing an individual entry has completed.
 106    /// </summary>
 107    EntryComplete,
 108
 109    /// <summary>
 110    /// Running miscellaneous tests
 111    /// </summary>
 112    MiscellaneousTests,
 113
 114    /// <summary>
 115    /// Testing is complete
 116    /// </summary>
 117    Complete,
 118  }
 119
 120  /// <summary>
 121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.
 122  /// </summary>
 123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 124  public class TestStatus
 125  {
 126    #region Constructors
 127    /// <summary>
 128    /// Initialise a new instance of <see cref="TestStatus"/>
 129    /// </summary>
 130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>
 131    public TestStatus(ZipFile file)
 132    {
 133      file_ = file;
 134    }
 135    #endregion
 136
 137    #region Properties
 138
 139    /// <summary>
 140    /// Get the current <see cref="TestOperation"/> in progress.
 141    /// </summary>
 142    public TestOperation Operation {
 143      get { return operation_; }
 144    }
 145
 146    /// <summary>
 147    /// Get the <see cref="ZipFile"/> this status is applicable to.
 148    /// </summary>
 149    public ZipFile File {
 150      get { return file_; }
 151    }
 152
 153    /// <summary>
 154    /// Get the current/last entry tested.
 155    /// </summary>
 156    public ZipEntry Entry {
 157      get { return entry_; }
 158    }
 159
 160    /// <summary>
 161    /// Get the number of errors detected so far.
 162    /// </summary>
 163    public int ErrorCount {
 164      get { return errorCount_; }
 165    }
 166
 167    /// <summary>
 168    /// Get the number of bytes tested so far for the current entry.
 169    /// </summary>
 170    public long BytesTested {
 171      get { return bytesTested_; }
 172    }
 173
 174    /// <summary>
 175    /// Get a value indicating wether the last entry test was valid.
 176    /// </summary>
 177    public bool EntryValid {
 178      get { return entryValid_; }
 179    }
 180    #endregion
 181
 182    #region Internal API
 183    internal void AddError()
 184    {
 185      errorCount_++;
 186      entryValid_ = false;
 187    }
 188
 189    internal void SetOperation(TestOperation operation)
 190    {
 191      operation_ = operation;
 192    }
 193
 194    internal void SetEntry(ZipEntry entry)
 195    {
 196      entry_ = entry;
 197      entryValid_ = true;
 198      bytesTested_ = 0;
 199    }
 200
 201    internal void SetBytesTested(long value)
 202    {
 203      bytesTested_ = value;
 204    }
 205    #endregion
 206
 207    #region Instance Fields
 208    ZipFile file_;
 209    ZipEntry entry_;
 210    bool entryValid_;
 211    int errorCount_;
 212    long bytesTested_;
 213    TestOperation operation_;
 214    #endregion
 215  }
 216
 217  /// <summary>
 218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if
 219  /// </summary>
 220  /// <remarks>If the message is non-null an error has occured.  If the message is null
 221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>
 222  public delegate void ZipTestResultHandler(TestStatus status, string message);
 223  #endregion
 224
 225  #region Update Definitions
 226  /// <summary>
 227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.
 228  /// </summary>
 229  public enum FileUpdateMode
 230  {
 231    /// <summary>
 232    /// Perform all updates on temporary files ensuring that the original file is saved.
 233    /// </summary>
 234    Safe,
 235    /// <summary>
 236    /// Update the archive directly, which is faster but less safe.
 237    /// </summary>
 238    Direct,
 239  }
 240  #endregion
 241
 242  #region ZipFile Class
 243  /// <summary>
 244  /// This class represents a Zip archive.  You can ask for the contained
 245  /// entries, or get an input stream for a file entry.  The entry is
 246  /// automatically decompressed.
 247  ///
 248  /// You can also update the archive adding or deleting entries.
 249  ///
 250  /// This class is thread safe for input:  You can open input streams for arbitrary
 251  /// entries in different threads.
 252  /// <br/>
 253  /// <br/>Author of the original java version : Jochen Hoenicke
 254  /// </summary>
 255  /// <example>
 256  /// <code>
 257  /// using System;
 258  /// using System.Text;
 259  /// using System.Collections;
 260  /// using System.IO;
 261  ///
 262  /// using ICSharpCode.SharpZipLib.Zip;
 263  ///
 264  /// class MainClass
 265  /// {
 266  ///   static public void Main(string[] args)
 267  ///   {
 268  ///     using (ZipFile zFile = new ZipFile(args[0])) {
 269  ///       Console.WriteLine("Listing of : " + zFile.Name);
 270  ///       Console.WriteLine("");
 271  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");
 272  ///       Console.WriteLine("--------  --------  --------  ------  ---------");
 273  ///       foreach (ZipEntry e in zFile) {
 274  ///         if ( e.IsFile ) {
 275  ///           DateTime d = e.DateTime;
 276  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,
 277  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),
 278  ///             e.Name);
 279  ///         }
 280  ///       }
 281  ///     }
 282  ///   }
 283  /// }
 284  /// </code>
 285  /// </example>
 286  public class ZipFile : IEnumerable, IDisposable
 287  {
 288    #region KeyHandling
 289
 290    /// <summary>
 291    /// Delegate for handling keys/password setting during compresion/decompression.
 292    /// </summary>
 293    public delegate void KeysRequiredEventHandler(
 294      object sender,
 295      KeysRequiredEventArgs e
 296    );
 297
 298    /// <summary>
 299    /// Event handler for handling encryption keys.
 300    /// </summary>
 301    public KeysRequiredEventHandler KeysRequired;
 302
 303    /// <summary>
 304    /// Handles getting of encryption keys when required.
 305    /// </summary>
 306    /// <param name="fileName">The file for which encryption keys are required.</param>
 307    void OnKeysRequired(string fileName)
 308    {
 309      if (KeysRequired != null) {
 310        var krea = new KeysRequiredEventArgs(fileName, key);
 311        KeysRequired(this, krea);
 312        key = krea.Key;
 313      }
 314    }
 315
 316    /// <summary>
 317    /// Get/set the encryption key value.
 318    /// </summary>
 319    byte[] Key {
 320      get { return key; }
 321      set { key = value; }
 322    }
 323
 324    /// <summary>
 325    /// Password to be used for encrypting/decrypting files.
 326    /// </summary>
 327    /// <remarks>Set to null if no password is required.</remarks>
 328    public string Password {
 329      set {
 330        if (string.IsNullOrEmpty(value)) {
 331          key = null;
 332        } else {
 333          rawPassword_ = value;
 334          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));
 335        }
 336      }
 337    }
 338
 339    /// <summary>
 340    /// Get a value indicating wether encryption keys are currently available.
 341    /// </summary>
 342    bool HaveKeys {
 343      get { return key != null; }
 344    }
 345    #endregion
 346
 347    #region Constructors
 348    /// <summary>
 349    /// Opens a Zip file with the given name for reading.
 350    /// </summary>
 351    /// <param name="name">The name of the file to open.</param>
 352    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>
 353    /// <exception cref="IOException">
 354    /// An i/o error occurs
 355    /// </exception>
 356    /// <exception cref="ZipException">
 357    /// The file doesn't contain a valid zip archive.
 358    /// </exception>
 359    public ZipFile(string name)
 360    {
 361      if (name == null) {
 362        throw new ArgumentNullException(nameof(name));
 363      }
 364
 365      name_ = name;
 366
 367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 368      isStreamOwner = true;
 369
 370      try {
 371        ReadEntries();
 372      } catch {
 373        DisposeInternal(true);
 374        throw;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Opens a Zip file reading the given <see cref="FileStream"/>.
 380    /// </summary>
 381    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>
 382    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>
 383    /// <exception cref="IOException">
 384    /// An i/o error occurs.
 385    /// </exception>
 386    /// <exception cref="ZipException">
 387    /// The file doesn't contain a valid zip archive.
 388    /// </exception>
 389    public ZipFile(FileStream file)
 390    {
 391      if (file == null) {
 392        throw new ArgumentNullException(nameof(file));
 393      }
 394
 395      if (!file.CanSeek) {
 396        throw new ArgumentException("Stream is not seekable", nameof(file));
 397      }
 398
 399      baseStream_ = file;
 400      name_ = file.Name;
 401      isStreamOwner = true;
 402
 403      try {
 404        ReadEntries();
 405      } catch {
 406        DisposeInternal(true);
 407        throw;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Opens a Zip file reading the given <see cref="Stream"/>.
 413    /// </summary>
 414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
 415    /// <exception cref="IOException">
 416    /// An i/o error occurs
 417    /// </exception>
 418    /// <exception cref="ZipException">
 419    /// The stream doesn't contain a valid zip archive.<br/>
 420    /// </exception>
 421    /// <exception cref="ArgumentException">
 422    /// The <see cref="Stream">stream</see> doesnt support seeking.
 423    /// </exception>
 424    /// <exception cref="ArgumentNullException">
 425    /// The <see cref="Stream">stream</see> argument is null.
 426    /// </exception>
 427    public ZipFile(Stream stream)
 428    {
 429      if (stream == null) {
 430        throw new ArgumentNullException(nameof(stream));
 431      }
 432
 433      if (!stream.CanSeek) {
 434        throw new ArgumentException("Stream is not seekable", nameof(stream));
 435      }
 436
 437      baseStream_ = stream;
 438      isStreamOwner = true;
 439
 440      if (baseStream_.Length > 0) {
 441        try {
 442          ReadEntries();
 443        } catch {
 444          DisposeInternal(true);
 445          throw;
 446        }
 447      } else {
 448        entries_ = new ZipEntry[0];
 449        isNewArchive_ = true;
 450      }
 451    }
 452
 453    /// <summary>
 454    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
 455    /// </summary>
 456    internal ZipFile()
 457    {
 458      entries_ = new ZipEntry[0];
 459      isNewArchive_ = true;
 460    }
 461
 462    #endregion
 463
 464    #region Destructors and Closing
 465    /// <summary>
 466    /// Finalize this instance.
 467    /// </summary>
 468    ~ZipFile()
 469    {
 470      Dispose(false);
 471    }
 472
 473    /// <summary>
 474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying
 475    /// Once closed, no further instance methods should be called.
 476    /// </summary>
 477    /// <exception cref="System.IO.IOException">
 478    /// An i/o error occurs.
 479    /// </exception>
 480    public void Close()
 481    {
 482      DisposeInternal(true);
 483      GC.SuppressFinalize(this);
 484    }
 485
 486    #endregion
 487
 488    #region Creators
 489    /// <summary>
 490    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.
 491    /// </summary>
 492    /// <param name="fileName">The name of the archive to create.</param>
 493    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 494    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>
 495    public static ZipFile Create(string fileName)
 496    {
 497      if (fileName == null) {
 498        throw new ArgumentNullException(nameof(fileName));
 499      }
 500
 501      FileStream fs = File.Create(fileName);
 502
 503      var result = new ZipFile();
 504      result.name_ = fileName;
 505      result.baseStream_ = fs;
 506      result.isStreamOwner = true;
 507      return result;
 508    }
 509
 510    /// <summary>
 511    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.
 512    /// </summary>
 513    /// <param name="outStream">The stream providing data storage.</param>
 514    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 515    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>
 516    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>
 517    public static ZipFile Create(Stream outStream)
 518    {
 519      if (outStream == null) {
 520        throw new ArgumentNullException(nameof(outStream));
 521      }
 522
 523      if (!outStream.CanWrite) {
 524        throw new ArgumentException("Stream is not writeable", nameof(outStream));
 525      }
 526
 527      if (!outStream.CanSeek) {
 528        throw new ArgumentException("Stream is not seekable", nameof(outStream));
 529      }
 530
 531      var result = new ZipFile();
 532      result.baseStream_ = outStream;
 533      return result;
 534    }
 535
 536    #endregion
 537
 538    #region Properties
 539    /// <summary>
 540    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
 541    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
 542    /// </summary>
 543    /// <remarks>
 544    /// The default value is true in all cases.
 545    /// </remarks>
 546    public bool IsStreamOwner {
 547      get { return isStreamOwner; }
 548      set { isStreamOwner = value; }
 549    }
 550
 551    /// <summary>
 552    /// Get a value indicating wether
 553    /// this archive is embedded in another file or not.
 554    /// </summary>
 555    public bool IsEmbeddedArchive {
 556      // Not strictly correct in all circumstances currently
 557      get { return offsetOfFirstEntry > 0; }
 558    }
 559
 560    /// <summary>
 561    /// Get a value indicating that this archive is a new one.
 562    /// </summary>
 563    public bool IsNewArchive {
 564      get { return isNewArchive_; }
 565    }
 566
 567    /// <summary>
 568    /// Gets the comment for the zip file.
 569    /// </summary>
 570    public string ZipFileComment {
 571      get { return comment_; }
 572    }
 573
 574    /// <summary>
 575    /// Gets the name of this zip file.
 576    /// </summary>
 577    public string Name {
 578      get { return name_; }
 579    }
 580
 581    /// <summary>
 582    /// Gets the number of entries in this zip file.
 583    /// </summary>
 584    /// <exception cref="InvalidOperationException">
 585    /// The Zip file has been closed.
 586    /// </exception>
 587    [Obsolete("Use the Count property instead")]
 588    public int Size {
 589      get {
 590        return entries_.Length;
 591      }
 592    }
 593
 594    /// <summary>
 595    /// Get the number of entries contained in this <see cref="ZipFile"/>.
 596    /// </summary>
 597    public long Count {
 598      get {
 599        return entries_.Length;
 600      }
 601    }
 602
 603    /// <summary>
 604    /// Indexer property for ZipEntries
 605    /// </summary>
 606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
 607    public ZipEntry this[int index] {
 608      get {
 609        return (ZipEntry)entries_[index].Clone();
 610      }
 611    }
 612
 613    #endregion
 614
 615    #region Input Handling
 616    /// <summary>
 617    /// Gets an enumerator for the Zip entries in this Zip file.
 618    /// </summary>
 619    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>
 620    /// <exception cref="ObjectDisposedException">
 621    /// The Zip file has been closed.
 622    /// </exception>
 623    public IEnumerator GetEnumerator()
 624    {
 625      if (isDisposed_) {
 626        throw new ObjectDisposedException("ZipFile");
 627      }
 628
 629      return new ZipEntryEnumerator(entries_);
 630    }
 631
 632    /// <summary>
 633    /// Return the index of the entry with a matching name
 634    /// </summary>
 635    /// <param name="name">Entry name to find</param>
 636    /// <param name="ignoreCase">If true the comparison is case insensitive</param>
 637    /// <returns>The index position of the matching entry or -1 if not found</returns>
 638    /// <exception cref="ObjectDisposedException">
 639    /// The Zip file has been closed.
 640    /// </exception>
 641    public int FindEntry(string name, bool ignoreCase)
 642    {
 643      if (isDisposed_) {
 644        throw new ObjectDisposedException("ZipFile");
 645      }
 646
 647      // TODO: This will be slow as the next ice age for huge archives!
 648      for (int i = 0; i < entries_.Length; i++) {
 649        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {
 650          return i;
 651        }
 652      }
 653      return -1;
 654    }
 655
 656    /// <summary>
 657    /// Searches for a zip entry in this archive with the given name.
 658    /// String comparisons are case insensitive
 659    /// </summary>
 660    /// <param name="name">
 661    /// The name to find. May contain directory components separated by slashes ('/').
 662    /// </param>
 663    /// <returns>
 664    /// A clone of the zip entry, or null if no entry with that name exists.
 665    /// </returns>
 666    /// <exception cref="ObjectDisposedException">
 667    /// The Zip file has been closed.
 668    /// </exception>
 669    public ZipEntry GetEntry(string name)
 670    {
 671      if (isDisposed_) {
 672        throw new ObjectDisposedException("ZipFile");
 673      }
 674
 675      int index = FindEntry(name, true);
 676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;
 677    }
 678
 679    /// <summary>
 680    /// Gets an input stream for reading the given zip entry data in an uncompressed form.
 681    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
 682    /// </summary>
 683    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
 684    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
 685    /// <exception cref="ObjectDisposedException">
 686    /// The ZipFile has already been closed
 687    /// </exception>
 688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 689    /// The compression method for the entry is unknown
 690    /// </exception>
 691    /// <exception cref="IndexOutOfRangeException">
 692    /// The entry is not found in the ZipFile
 693    /// </exception>
 694    public Stream GetInputStream(ZipEntry entry)
 695    {
 696      if (entry == null) {
 697        throw new ArgumentNullException(nameof(entry));
 698      }
 699
 700      if (isDisposed_) {
 701        throw new ObjectDisposedException("ZipFile");
 702      }
 703
 704      long index = entry.ZipFileIndex;
 705      if ((index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name)) {
 706        index = FindEntry(entry.Name, true);
 707        if (index < 0) {
 708          throw new ZipException("Entry cannot be found");
 709        }
 710      }
 711      return GetInputStream(index);
 712    }
 713
 714    /// <summary>
 715    /// Creates an input stream reading a zip entry
 716    /// </summary>
 717    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
 718    /// <returns>
 719    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>
 720    /// </returns>
 721    /// <exception cref="ObjectDisposedException">
 722    /// The ZipFile has already been closed
 723    /// </exception>
 724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 725    /// The compression method for the entry is unknown
 726    /// </exception>
 727    /// <exception cref="IndexOutOfRangeException">
 728    /// The entry is not found in the ZipFile
 729    /// </exception>
 730    public Stream GetInputStream(long entryIndex)
 731    {
 732      if (isDisposed_) {
 733        throw new ObjectDisposedException("ZipFile");
 734      }
 735
 736      long start = LocateEntry(entries_[entryIndex]);
 737      CompressionMethod method = entries_[entryIndex].CompressionMethod;
 738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);
 739
 740      if (entries_[entryIndex].IsCrypted == true) {
 741        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);
 742        if (result == null) {
 743          throw new ZipException("Unable to decrypt this entry");
 744        }
 745      }
 746
 747      switch (method) {
 748        case CompressionMethod.Stored:
 749          // read as is.
 750          break;
 751
 752        case CompressionMethod.Deflated:
 753          // No need to worry about ownership and closing as underlying stream close does nothing.
 754          result = new InflaterInputStream(result, new Inflater(true));
 755          break;
 756
 757        default:
 758          throw new ZipException("Unsupported compression method " + method);
 759      }
 760
 761      return result;
 762    }
 763
 764    #endregion
 765
 766    #region Archive Testing
 767    /// <summary>
 768    /// Test an archive for integrity/validity
 769    /// </summary>
 770    /// <param name="testData">Perform low level data Crc check</param>
 771    /// <returns>true if all tests pass, false otherwise</returns>
 772    /// <remarks>Testing will terminate on the first error found.</remarks>
 773    public bool TestArchive(bool testData)
 774    {
 775      return TestArchive(testData, TestStrategy.FindFirstError, null);
 776    }
 777
 778    /// <summary>
 779    /// Test an archive for integrity/validity
 780    /// </summary>
 781    /// <param name="testData">Perform low level data Crc check</param>
 782    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
 783    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
 784    /// <returns>true if all tests pass, false otherwise</returns>
 785    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>
 786    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
 787    {
 788      if (isDisposed_) {
 789        throw new ObjectDisposedException("ZipFile");
 790      }
 791
 792      var status = new TestStatus(this);
 793
 794      if (resultHandler != null) {
 795        resultHandler(status, null);
 796      }
 797
 798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;
 799
 800      bool testing = true;
 801
 802      try {
 803        int entryIndex = 0;
 804
 805        while (testing && (entryIndex < Count)) {
 806          if (resultHandler != null) {
 807            status.SetEntry(this[entryIndex]);
 808            status.SetOperation(TestOperation.EntryHeader);
 809            resultHandler(status, null);
 810          }
 811
 812          try {
 813            TestLocalHeader(this[entryIndex], test);
 814          } catch (ZipException ex) {
 815            status.AddError();
 816
 817            if (resultHandler != null) {
 818              resultHandler(status,
 819                string.Format("Exception during test - '{0}'", ex.Message));
 820            }
 821
 822            testing &= strategy != TestStrategy.FindFirstError;
 823          }
 824
 825          if (testing && testData && this[entryIndex].IsFile) {
 826            if (resultHandler != null) {
 827              status.SetOperation(TestOperation.EntryData);
 828              resultHandler(status, null);
 829            }
 830
 831            var crc = new Crc32();
 832
 833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {
 834
 835              byte[] buffer = new byte[4096];
 836              long totalBytes = 0;
 837              int bytesRead;
 838              while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
 839                crc.Update(buffer, 0, bytesRead);
 840
 841                if (resultHandler != null) {
 842                  totalBytes += bytesRead;
 843                  status.SetBytesTested(totalBytes);
 844                  resultHandler(status, null);
 845                }
 846              }
 847            }
 848
 849            if (this[entryIndex].Crc != crc.Value) {
 850              status.AddError();
 851
 852              if (resultHandler != null) {
 853                resultHandler(status, "CRC mismatch");
 854              }
 855
 856              testing &= strategy != TestStrategy.FindFirstError;
 857            }
 858
 859            if ((this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 860              var helper = new ZipHelperStream(baseStream_);
 861              var data = new DescriptorData();
 862              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
 863              if (this[entryIndex].Crc != data.Crc) {
 864                status.AddError();
 865              }
 866
 867              if (this[entryIndex].CompressedSize != data.CompressedSize) {
 868                status.AddError();
 869              }
 870
 871              if (this[entryIndex].Size != data.Size) {
 872                status.AddError();
 873              }
 874            }
 875          }
 876
 877          if (resultHandler != null) {
 878            status.SetOperation(TestOperation.EntryComplete);
 879            resultHandler(status, null);
 880          }
 881
 882          entryIndex += 1;
 883        }
 884
 885        if (resultHandler != null) {
 886          status.SetOperation(TestOperation.MiscellaneousTests);
 887          resultHandler(status, null);
 888        }
 889
 890        // TODO: the 'Corrina Johns' test where local headers are missing from
 891        // the central directory.  They are therefore invisible to many archivers.
 892      } catch (Exception ex) {
 893        status.AddError();
 894
 895        if (resultHandler != null) {
 896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
 897        }
 898      }
 899
 900      if (resultHandler != null) {
 901        status.SetOperation(TestOperation.Complete);
 902        status.SetEntry(null);
 903        resultHandler(status, null);
 904      }
 905
 906      return (status.ErrorCount == 0);
 907    }
 908
 909    [Flags]
 910    enum HeaderTest
 911    {
 912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted
 913      Header = 0x02,     // Check that this header contents are valid
 914    }
 915
 916    /// <summary>
 917    /// Test a local header against that provided from the central directory
 918    /// </summary>
 919    /// <param name="entry">
 920    /// The entry to test against
 921    /// </param>
 922    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
 923    /// <returns>The offset of the entries data in the file</returns>
 924    long TestLocalHeader(ZipEntry entry, HeaderTest tests)
 925    {
 926      lock (baseStream_) {
 927        bool testHeader = (tests & HeaderTest.Header) != 0;
 928        bool testData = (tests & HeaderTest.Extract) != 0;
 929
 930        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
 931        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
 932          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)
 933        }
 934
 935        var extractVersion = (short)(ReadLEUshort() & 0x00ff);
 936        var localFlags = (short)ReadLEUshort();
 937        var compressionMethod = (short)ReadLEUshort();
 938        var fileTime = (short)ReadLEUshort();
 939        var fileDate = (short)ReadLEUshort();
 940        uint crcValue = ReadLEUint();
 941        long compressedSize = ReadLEUint();
 942        long size = ReadLEUint();
 943        int storedNameLength = ReadLEUshort();
 944        int extraDataLength = ReadLEUshort();
 945
 946        byte[] nameData = new byte[storedNameLength];
 947        StreamUtils.ReadFully(baseStream_, nameData);
 948
 949        byte[] extraData = new byte[extraDataLength];
 950        StreamUtils.ReadFully(baseStream_, extraData);
 951
 952        var localExtraData = new ZipExtraData(extraData);
 953
 954        // Extra data / zip64 checks
 955        if (localExtraData.Find(1)) {
 956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
 957          // and size or compressedSize = MaxValue, due to rogue creators.
 958
 959          size = localExtraData.ReadLong();
 960          compressedSize = localExtraData.ReadLong();
 961
 962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {
 963            // These may be valid if patched later
 964            if ((size != -1) && (size != entry.Size)) {
 965              throw new ZipException("Size invalid for descriptor");
 966            }
 967
 968            if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {
 969              throw new ZipException("Compressed size invalid for descriptor");
 970            }
 971          }
 972        } else {
 973          // No zip64 extra data but entry requires it.
 974          if ((extractVersion >= ZipConstants.VersionZip64) &&
 975            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) {
 976            throw new ZipException("Required Zip64 extended information missing");
 977          }
 978        }
 979
 980        if (testData) {
 981          if (entry.IsFile) {
 982            if (!entry.IsCompressionMethodSupported()) {
 983              throw new ZipException("Compression method not supported");
 984            }
 985
 986            if ((extractVersion > ZipConstants.VersionMadeBy)
 987              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64))) {
 988              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract
 989            }
 990
 991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance
 992              throw new ZipException("The library does not support the zip version required to extract this entry");
 993            }
 994          }
 995        }
 996
 997        if (testHeader) {
 998          if ((extractVersion <= 63) &&   // Ignore later versions as we dont know about them..
 999            (extractVersion != 10) &&
 1000            (extractVersion != 11) &&
 1001            (extractVersion != 20) &&
 1002            (extractVersion != 21) &&
 1003            (extractVersion != 25) &&
 1004            (extractVersion != 27) &&
 1005            (extractVersion != 45) &&
 1006            (extractVersion != 46) &&
 1007            (extractVersion != 50) &&
 1008            (extractVersion != 51) &&
 1009            (extractVersion != 52) &&
 1010            (extractVersion != 61) &&
 1011            (extractVersion != 62) &&
 1012            (extractVersion != 63)
 1013            ) {
 1014            throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersi
 1015          }
 1016
 1017          // Local entry flags dont have reserved bit set on.
 1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R
 1019            throw new ZipException("Reserved bit flags cannot be set.");
 1020          }
 1021
 1022          // Encryption requires extract version >= 20
 1023          if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) {
 1024            throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})
 1025          }
 1026
 1027          // Strong encryption requires encryption flag to be set and extract version >= 50.
 1028          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1029            if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) {
 1030              throw new ZipException("Strong encryption flag set but encryption flag is not set");
 1031            }
 1032
 1033            if (extractVersion < 50) {
 1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0
 1035            }
 1036          }
 1037
 1038          // Patched entries require extract version >= 27
 1039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {
 1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
 1041          }
 1042
 1043          // Central header flags match local entry flags.
 1044          if (localFlags != entry.Flags) {
 1045            throw new ZipException("Central header/local header flags mismatch");
 1046          }
 1047
 1048          // Central header compression method matches local entry
 1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {
 1050            throw new ZipException("Central header/local header compression method mismatch");
 1051          }
 1052
 1053          if (entry.Version != extractVersion) {
 1054            throw new ZipException("Extract version mismatch");
 1055          }
 1056
 1057          // Strong encryption and extract version match
 1058          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1059            if (extractVersion < 62) {
 1060              throw new ZipException("Strong encryption flag set but version not high enough");
 1061            }
 1062          }
 1063
 1064          if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) {
 1065            if ((fileTime != 0) || (fileDate != 0)) {
 1066              throw new ZipException("Header masked set but date/time values non-zero");
 1067            }
 1068          }
 1069
 1070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
 1071            if (crcValue != (uint)entry.Crc) {
 1072              throw new ZipException("Central header/local header crc mismatch");
 1073            }
 1074          }
 1075
 1076          // Crc valid for empty entry.
 1077          // This will also apply to streamed entries where size isnt known and the header cant be patched
 1078          if ((size == 0) && (compressedSize == 0)) {
 1079            if (crcValue != 0) {
 1080              throw new ZipException("Invalid CRC for empty entry");
 1081            }
 1082          }
 1083
 1084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str
 1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
 1086          if (entry.Name.Length > storedNameLength) {
 1087            throw new ZipException("File name length mismatch");
 1088          }
 1089
 1090          // Name data has already been read convert it and compare.
 1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);
 1092
 1093          // Central directory and local entry name match
 1094          if (localName != entry.Name) {
 1095            throw new ZipException("Central header and local header file name mismatch");
 1096          }
 1097
 1098          // Directories have zero actual size but can have compressed size
 1099          if (entry.IsDirectory) {
 1100            if (size > 0) {
 1101              throw new ZipException("Directory cannot have size");
 1102            }
 1103
 1104            // There may be other cases where the compressed size can be greater than this?
 1105            // If so until details are known we will be strict.
 1106            if (entry.IsCrypted) {
 1107              if (compressedSize > ZipConstants.CryptoHeaderSize + 2) {
 1108                throw new ZipException("Directory compressed size invalid");
 1109              }
 1110            } else if (compressedSize > 2) {
 1111              // When not compressed the directory size can validly be 2 bytes
 1112              // if the true size wasnt known when data was originally being written.
 1113              // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
 1114              throw new ZipException("Directory compressed size invalid");
 1115            }
 1116          }
 1117
 1118          if (!ZipNameTransform.IsValidName(localName, true)) {
 1119            throw new ZipException("Name is invalid");
 1120          }
 1121        }
 1122
 1123        // Tests that apply to both data and header.
 1124
 1125        // Size can be verified only if it is known in the local header.
 1126        // it will always be known in the central header.
 1127        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
 1128          ((size > 0 || compressedSize > 0) && entry.Size > 0)) {
 1129
 1130          if ((size != 0)
 1131            && (size != entry.Size)) {
 1132            throw new ZipException(
 1133              string.Format("Size mismatch between central header({0}) and local header({1})",
 1134                entry.Size, size));
 1135          }
 1136
 1137          if ((compressedSize != 0)
 1138            && (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) {
 1139            throw new ZipException(
 1140              string.Format("Compressed size mismatch between central header({0}) and local header({1})",
 1141              entry.CompressedSize, compressedSize));
 1142          }
 1143        }
 1144
 1145        int extraLength = storedNameLength + extraDataLength;
 1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
 1147      }
 1148    }
 1149
 1150    #endregion
 1151
 1152    #region Updating
 1153
 1154    const int DefaultBufferSize = 4096;
 1155
 1156    /// <summary>
 1157    /// The kind of update to apply.
 1158    /// </summary>
 1159    enum UpdateCommand
 1160    {
 1161      Copy,       // Copy original file contents.
 1162      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.
 1163      Add,        // Add a new file to the archive.
 1164    }
 1165
 1166    #region Properties
 1167    /// <summary>
 1168    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.
 1169    /// </summary>
 1170    public INameTransform NameTransform {
 1171      get {
 1172        return updateEntryFactory_.NameTransform;
 1173      }
 1174
 1175      set {
 1176        updateEntryFactory_.NameTransform = value;
 1177      }
 1178    }
 1179
 1180    /// <summary>
 1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values
 1182    /// during updates.
 1183    /// </summary>
 1184    public IEntryFactory EntryFactory {
 1185      get {
 1186        return updateEntryFactory_;
 1187      }
 1188
 1189      set {
 1190        if (value == null) {
 1191          updateEntryFactory_ = new ZipEntryFactory();
 1192        } else {
 1193          updateEntryFactory_ = value;
 1194        }
 1195      }
 1196    }
 1197
 1198    /// <summary>
 1199    /// Get /set the buffer size to be used when updating this zip file.
 1200    /// </summary>
 1201    public int BufferSize {
 1202      get { return bufferSize_; }
 1203      set {
 1204        if (value < 1024) {
 1205          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");
 1206        }
 1207
 1208        if (bufferSize_ != value) {
 1209          bufferSize_ = value;
 1210          copyBuffer_ = null;
 1211        }
 1212      }
 1213    }
 1214
 1215    /// <summary>
 1216    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.
 1217    /// </summary>
 1218    public bool IsUpdating {
 1219      get { return updates_ != null; }
 1220    }
 1221
 1222    /// <summary>
 1223    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
 1224    /// </summary>
 1225    public UseZip64 UseZip64 {
 1226      get { return useZip64_; }
 1227      set { useZip64_ = value; }
 1228    }
 1229
 1230    #endregion
 1231
 1232    #region Immediate updating
 1233    //    TBD: Direct form of updating
 1234    //
 1235    //    public void Update(IEntryMatcher deleteMatcher)
 1236    //    {
 1237    //    }
 1238    //
 1239    //    public void Update(IScanner addScanner)
 1240    //    {
 1241    //    }
 1242    #endregion
 1243
 1244    #region Deferred Updating
 1245    /// <summary>
 1246    /// Begin updating this <see cref="ZipFile"/> archive.
 1247    /// </summary>
 1248    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p
 1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param
 1250    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1251    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>
 1252    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1253    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)
 1254    {
 1255      if (archiveStorage == null) {
 1256        throw new ArgumentNullException(nameof(archiveStorage));
 1257      }
 1258
 1259      if (dataSource == null) {
 1260        throw new ArgumentNullException(nameof(dataSource));
 1261      }
 1262
 1263      if (isDisposed_) {
 1264        throw new ObjectDisposedException("ZipFile");
 1265      }
 1266
 1267      if (IsEmbeddedArchive) {
 1268        throw new ZipException("Cannot update embedded/SFX archives");
 1269      }
 1270
 1271      archiveStorage_ = archiveStorage;
 1272      updateDataSource_ = dataSource;
 1273
 1274      // NOTE: the baseStream_ may not currently support writing or seeking.
 1275
 1276      updateIndex_ = new Hashtable();
 1277
 1278      updates_ = new ArrayList(entries_.Length);
 1279      foreach (ZipEntry entry in entries_) {
 1280        int index = updates_.Add(new ZipUpdate(entry));
 1281        updateIndex_.Add(entry.Name, index);
 1282      }
 1283
 1284      // We must sort by offset before using offset's calculated sizes
 1285      updates_.Sort(new UpdateComparer());
 1286
 1287      int idx = 0;
 1288      foreach (ZipUpdate update in updates_) {
 1289        //If last entry, there is no next entry offset to use
 1290        if (idx == updates_.Count - 1)
 1291          break;
 1292
 1293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;
 1294        idx++;
 1295      }
 1296      updateCount_ = updates_.Count;
 1297
 1298      contentsEdited_ = false;
 1299      commentEdited_ = false;
 1300      newComment_ = null;
 1301    }
 1302
 1303    /// <summary>
 1304    /// Begin updating to this <see cref="ZipFile"/> archive.
 1305    /// </summary>
 1306    /// <param name="archiveStorage">The storage to use during the update.</param>
 1307    public void BeginUpdate(IArchiveStorage archiveStorage)
 1308    {
 1309      BeginUpdate(archiveStorage, new DynamicDiskDataSource());
 1310    }
 1311
 1312    /// <summary>
 1313    /// Begin updating this <see cref="ZipFile"/> archive.
 1314    /// </summary>
 1315    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>
 1316    /// <seealso cref="CommitUpdate"></seealso>
 1317    /// <seealso cref="AbortUpdate"></seealso>
 1318    public void BeginUpdate()
 1319    {
 1320      if (Name == null) {
 1321        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());
 1322      } else {
 1323        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());
 1324      }
 1325    }
 1326
 1327    /// <summary>
 1328    /// Commit current updates, updating this archive.
 1329    /// </summary>
 1330    /// <seealso cref="BeginUpdate()"></seealso>
 1331    /// <seealso cref="AbortUpdate"></seealso>
 1332    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1333    public void CommitUpdate()
 1334    {
 1335      if (isDisposed_) {
 1336        throw new ObjectDisposedException("ZipFile");
 1337      }
 1338
 1339      CheckUpdating();
 1340
 1341      try {
 1342        updateIndex_.Clear();
 1343        updateIndex_ = null;
 1344
 1345        if (contentsEdited_) {
 1346          RunUpdates();
 1347        } else if (commentEdited_) {
 1348          UpdateCommentOnly();
 1349        } else {
 1350          // Create an empty archive if none existed originally.
 1351          if (entries_.Length == 0) {
 1352            byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 1353            using (ZipHelperStream zhs = new ZipHelperStream(baseStream_)) {
 1354              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
 1355            }
 1356          }
 1357        }
 1358
 1359      } finally {
 1360        PostUpdateCleanup();
 1361      }
 1362    }
 1363
 1364    /// <summary>
 1365    /// Abort updating leaving the archive unchanged.
 1366    /// </summary>
 1367    /// <seealso cref="BeginUpdate()"></seealso>
 1368    /// <seealso cref="CommitUpdate"></seealso>
 1369    public void AbortUpdate()
 1370    {
 1371      PostUpdateCleanup();
 1372    }
 1373
 1374    /// <summary>
 1375    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.
 1376    /// </summary>
 1377    /// <param name="comment">The comment to record.</param>
 1378    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1379    public void SetComment(string comment)
 1380    {
 1381      if (isDisposed_) {
 1382        throw new ObjectDisposedException("ZipFile");
 1383      }
 1384
 1385      CheckUpdating();
 1386
 1387      newComment_ = new ZipString(comment);
 1388
 1389      if (newComment_.RawLength > 0xffff) {
 1390        newComment_ = null;
 1391        throw new ZipException("Comment length exceeds maximum - 65535");
 1392      }
 1393
 1394      // We dont take account of the original and current comment appearing to be the same
 1395      // as encoding may be different.
 1396      commentEdited_ = true;
 1397    }
 1398
 1399    #endregion
 1400
 1401    #region Adding Entries
 1402
 1403    void AddUpdate(ZipUpdate update)
 1404    {
 1405      contentsEdited_ = true;
 1406
 1407      int index = FindExistingUpdate(update.Entry.Name);
 1408
 1409      if (index >= 0) {
 1410        if (updates_[index] == null) {
 1411          updateCount_ += 1;
 1412        }
 1413
 1414        // Direct replacement is faster than delete and add.
 1415        updates_[index] = update;
 1416      } else {
 1417        index = updates_.Add(update);
 1418        updateCount_ += 1;
 1419        updateIndex_.Add(update.Entry.Name, index);
 1420      }
 1421    }
 1422
 1423    /// <summary>
 1424    /// Add a new entry to the archive.
 1425    /// </summary>
 1426    /// <param name="fileName">The name of the file to add.</param>
 1427    /// <param name="compressionMethod">The compression method to use.</param>
 1428    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>
 1429    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1430    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1431    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>
 1432    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText)
 1433    {
 1434      if (fileName == null) {
 1435        throw new ArgumentNullException(nameof(fileName));
 1436      }
 1437
 1438      if (isDisposed_) {
 1439        throw new ObjectDisposedException("ZipFile");
 1440      }
 1441
 1442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1444      }
 1445
 1446      CheckUpdating();
 1447      contentsEdited_ = true;
 1448
 1449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1450      entry.IsUnicodeText = useUnicodeText;
 1451      entry.CompressionMethod = compressionMethod;
 1452
 1453      AddUpdate(new ZipUpdate(fileName, entry));
 1454    }
 1455
 1456    /// <summary>
 1457    /// Add a new entry to the archive.
 1458    /// </summary>
 1459    /// <param name="fileName">The name of the file to add.</param>
 1460    /// <param name="compressionMethod">The compression method to use.</param>
 1461    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>
 1462    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>
 1463    public void Add(string fileName, CompressionMethod compressionMethod)
 1464    {
 1465      if (fileName == null) {
 1466        throw new ArgumentNullException(nameof(fileName));
 1467      }
 1468
 1469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1471      }
 1472
 1473      CheckUpdating();
 1474      contentsEdited_ = true;
 1475
 1476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1477      entry.CompressionMethod = compressionMethod;
 1478      AddUpdate(new ZipUpdate(fileName, entry));
 1479    }
 1480
 1481    /// <summary>
 1482    /// Add a file to the archive.
 1483    /// </summary>
 1484    /// <param name="fileName">The name of the file to add.</param>
 1485    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1486    public void Add(string fileName)
 1487    {
 1488      if (fileName == null) {
 1489        throw new ArgumentNullException(nameof(fileName));
 1490      }
 1491
 1492      CheckUpdating();
 1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));
 1494    }
 1495
 1496    /// <summary>
 1497    /// Add a file to the archive.
 1498    /// </summary>
 1499    /// <param name="fileName">The name of the file to add.</param>
 1500    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>
 1501    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1502    public void Add(string fileName, string entryName)
 1503    {
 1504      if (fileName == null) {
 1505        throw new ArgumentNullException(nameof(fileName));
 1506      }
 1507
 1508      if (entryName == null) {
 1509        throw new ArgumentNullException(nameof(entryName));
 1510      }
 1511
 1512      CheckUpdating();
 1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));
 1514    }
 1515
 1516
 1517    /// <summary>
 1518    /// Add a file entry with data.
 1519    /// </summary>
 1520    /// <param name="dataSource">The source of the data for this entry.</param>
 1521    /// <param name="entryName">The name to give to the entry.</param>
 1522    public void Add(IStaticDataSource dataSource, string entryName)
 1523    {
 1524      if (dataSource == null) {
 1525        throw new ArgumentNullException(nameof(dataSource));
 1526      }
 1527
 1528      if (entryName == null) {
 1529        throw new ArgumentNullException(nameof(entryName));
 1530      }
 1531
 1532      CheckUpdating();
 1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));
 1534    }
 1535
 1536    /// <summary>
 1537    /// Add a file entry with data.
 1538    /// </summary>
 1539    /// <param name="dataSource">The source of the data for this entry.</param>
 1540    /// <param name="entryName">The name to give to the entry.</param>
 1541    /// <param name="compressionMethod">The compression method to use.</param>
 1542    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 1543    {
 1544      if (dataSource == null) {
 1545        throw new ArgumentNullException(nameof(dataSource));
 1546      }
 1547
 1548      if (entryName == null) {
 1549        throw new ArgumentNullException(nameof(entryName));
 1550      }
 1551
 1552      CheckUpdating();
 1553
 1554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1555      entry.CompressionMethod = compressionMethod;
 1556
 1557      AddUpdate(new ZipUpdate(dataSource, entry));
 1558    }
 1559
 1560    /// <summary>
 1561    /// Add a file entry with data.
 1562    /// </summary>
 1563    /// <param name="dataSource">The source of the data for this entry.</param>
 1564    /// <param name="entryName">The name to give to the entry.</param>
 1565    /// <param name="compressionMethod">The compression method to use.</param>
 1566    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>
 1567    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode
 1568    {
 1569      if (dataSource == null) {
 1570        throw new ArgumentNullException(nameof(dataSource));
 1571      }
 1572
 1573      if (entryName == null) {
 1574        throw new ArgumentNullException(nameof(entryName));
 1575      }
 1576
 1577      CheckUpdating();
 1578
 1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1580      entry.IsUnicodeText = useUnicodeText;
 1581      entry.CompressionMethod = compressionMethod;
 1582
 1583      AddUpdate(new ZipUpdate(dataSource, entry));
 1584    }
 1585
 1586    /// <summary>
 1587    /// Add a <see cref="ZipEntry"/> that contains no data.
 1588    /// </summary>
 1589    /// <param name="entry">The entry to add.</param>
 1590    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
 1591    public void Add(ZipEntry entry)
 1592    {
 1593      if (entry == null) {
 1594        throw new ArgumentNullException(nameof(entry));
 1595      }
 1596
 1597      CheckUpdating();
 1598
 1599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {
 1600        throw new ZipException("Entry cannot have any data");
 1601      }
 1602
 1603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
 1604    }
 1605
 1606    /// <summary>
 1607    /// Add a directory entry to the archive.
 1608    /// </summary>
 1609    /// <param name="directoryName">The directory to add.</param>
 1610    public void AddDirectory(string directoryName)
 1611    {
 1612      if (directoryName == null) {
 1613        throw new ArgumentNullException(nameof(directoryName));
 1614      }
 1615
 1616      CheckUpdating();
 1617
 1618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);
 1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));
 1620    }
 1621
 1622    #endregion
 1623
 1624    #region Modifying Entries
 1625    /* Modify not yet ready for public consumption.
 1626       Direct modification of an entry should not overwrite original data before its read.
 1627       Safe mode is trivial in this sense.
 1628        public void Modify(ZipEntry original, ZipEntry updated)
 1629        {
 1630          if ( original == null ) {
 1631            throw new ArgumentNullException("original");
 1632          }
 1633
 1634          if ( updated == null ) {
 1635            throw new ArgumentNullException("updated");
 1636          }
 1637
 1638          CheckUpdating();
 1639          contentsEdited_ = true;
 1640          updates_.Add(new ZipUpdate(original, updated));
 1641        }
 1642    */
 1643    #endregion
 1644
 1645    #region Deleting Entries
 1646    /// <summary>
 1647    /// Delete an entry by name
 1648    /// </summary>
 1649    /// <param name="fileName">The filename to delete</param>
 1650    /// <returns>True if the entry was found and deleted; false otherwise.</returns>
 1651    public bool Delete(string fileName)
 1652    {
 1653      if (fileName == null) {
 1654        throw new ArgumentNullException(nameof(fileName));
 1655      }
 1656
 1657      CheckUpdating();
 1658
 1659      bool result = false;
 1660      int index = FindExistingUpdate(fileName);
 1661      if ((index >= 0) && (updates_[index] != null)) {
 1662        result = true;
 1663        contentsEdited_ = true;
 1664        updates_[index] = null;
 1665        updateCount_ -= 1;
 1666      } else {
 1667        throw new ZipException("Cannot find entry to delete");
 1668      }
 1669      return result;
 1670    }
 1671
 1672    /// <summary>
 1673    /// Delete a <see cref="ZipEntry"/> from the archive.
 1674    /// </summary>
 1675    /// <param name="entry">The entry to delete.</param>
 1676    public void Delete(ZipEntry entry)
 1677    {
 1678      if (entry == null) {
 1679        throw new ArgumentNullException(nameof(entry));
 1680      }
 1681
 1682      CheckUpdating();
 1683
 1684      int index = FindExistingUpdate(entry);
 1685      if (index >= 0) {
 1686        contentsEdited_ = true;
 1687        updates_[index] = null;
 1688        updateCount_ -= 1;
 1689      } else {
 1690        throw new ZipException("Cannot find entry to delete");
 1691      }
 1692    }
 1693
 1694    #endregion
 1695
 1696    #region Update Support
 1697
 1698    #region Writing Values/Headers
 1699    void WriteLEShort(int value)
 1700    {
 1701      baseStream_.WriteByte((byte)(value & 0xff));
 1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));
 1703    }
 1704
 1705    /// <summary>
 1706    /// Write an unsigned short in little endian byte order.
 1707    /// </summary>
 1708    void WriteLEUshort(ushort value)
 1709    {
 1710      baseStream_.WriteByte((byte)(value & 0xff));
 1711      baseStream_.WriteByte((byte)(value >> 8));
 1712    }
 1713
 1714    /// <summary>
 1715    /// Write an int in little endian byte order.
 1716    /// </summary>
 1717    void WriteLEInt(int value)
 1718    {
 1719      WriteLEShort(value & 0xffff);
 1720      WriteLEShort(value >> 16);
 1721    }
 1722
 1723    /// <summary>
 1724    /// Write an unsigned int in little endian byte order.
 1725    /// </summary>
 1726    void WriteLEUint(uint value)
 1727    {
 1728      WriteLEUshort((ushort)(value & 0xffff));
 1729      WriteLEUshort((ushort)(value >> 16));
 1730    }
 1731
 1732    /// <summary>
 1733    /// Write a long in little endian byte order.
 1734    /// </summary>
 1735    void WriteLeLong(long value)
 1736    {
 1737      WriteLEInt((int)(value & 0xffffffff));
 1738      WriteLEInt((int)(value >> 32));
 1739    }
 1740
 1741    void WriteLEUlong(ulong value)
 1742    {
 1743      WriteLEUint((uint)(value & 0xffffffff));
 1744      WriteLEUint((uint)(value >> 32));
 1745    }
 1746
 1747    void WriteLocalEntryHeader(ZipUpdate update)
 1748    {
 1749      ZipEntry entry = update.OutEntry;
 1750
 1751      // TODO: Local offset will require adjusting for multi-disk zip files.
 1752      entry.Offset = baseStream_.Position;
 1753
 1754      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
 1755      if (update.Command != UpdateCommand.Copy) {
 1756        if (entry.CompressionMethod == CompressionMethod.Deflated) {
 1757          if (entry.Size == 0) {
 1758            // No need to compress - no data.
 1759            entry.CompressedSize = entry.Size;
 1760            entry.Crc = 0;
 1761            entry.CompressionMethod = CompressionMethod.Stored;
 1762          }
 1763        } else if (entry.CompressionMethod == CompressionMethod.Stored) {
 1764          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
 1765        }
 1766
 1767        if (HaveKeys) {
 1768          entry.IsCrypted = true;
 1769          if (entry.Crc < 0) {
 1770            entry.Flags |= (int)GeneralBitFlags.Descriptor;
 1771          }
 1772        } else {
 1773          entry.IsCrypted = false;
 1774        }
 1775
 1776        switch (useZip64_) {
 1777          case UseZip64.Dynamic:
 1778            if (entry.Size < 0) {
 1779              entry.ForceZip64();
 1780            }
 1781            break;
 1782
 1783          case UseZip64.On:
 1784            entry.ForceZip64();
 1785            break;
 1786
 1787          case UseZip64.Off:
 1788            // Do nothing.  The entry itself may be using Zip64 independantly.
 1789            break;
 1790        }
 1791      }
 1792
 1793      // Write the local file header
 1794      WriteLEInt(ZipConstants.LocalHeaderSignature);
 1795
 1796      WriteLEShort(entry.Version);
 1797      WriteLEShort(entry.Flags);
 1798
 1799      WriteLEShort((byte)entry.CompressionMethod);
 1800      WriteLEInt((int)entry.DosTime);
 1801
 1802      if (!entry.HasCrc) {
 1803        // Note patch address for updating CRC later.
 1804        update.CrcPatchOffset = baseStream_.Position;
 1805        WriteLEInt((int)0);
 1806      } else {
 1807        WriteLEInt(unchecked((int)entry.Crc));
 1808      }
 1809
 1810      if (entry.LocalHeaderRequiresZip64) {
 1811        WriteLEInt(-1);
 1812        WriteLEInt(-1);
 1813      } else {
 1814        if ((entry.CompressedSize < 0) || (entry.Size < 0)) {
 1815          update.SizePatchOffset = baseStream_.Position;
 1816        }
 1817
 1818        WriteLEInt((int)entry.CompressedSize);
 1819        WriteLEInt((int)entry.Size);
 1820      }
 1821
 1822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1823
 1824      if (name.Length > 0xFFFF) {
 1825        throw new ZipException("Entry name too long.");
 1826      }
 1827
 1828      var ed = new ZipExtraData(entry.ExtraData);
 1829
 1830      if (entry.LocalHeaderRequiresZip64) {
 1831        ed.StartNewEntry();
 1832
 1833        // Local entry header always includes size and compressed size.
 1834        // NOTE the order of these fields is reversed when compared to the normal headers!
 1835        ed.AddLeLong(entry.Size);
 1836        ed.AddLeLong(entry.CompressedSize);
 1837        ed.AddNewEntry(1);
 1838      } else {
 1839        ed.Delete(1);
 1840      }
 1841
 1842      entry.ExtraData = ed.GetEntryData();
 1843
 1844      WriteLEShort(name.Length);
 1845      WriteLEShort(entry.ExtraData.Length);
 1846
 1847      if (name.Length > 0) {
 1848        baseStream_.Write(name, 0, name.Length);
 1849      }
 1850
 1851      if (entry.LocalHeaderRequiresZip64) {
 1852        if (!ed.Find(1)) {
 1853          throw new ZipException("Internal error cannot find extra data");
 1854        }
 1855
 1856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
 1857      }
 1858
 1859      if (entry.ExtraData.Length > 0) {
 1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
 1861      }
 1862    }
 1863
 1864    int WriteCentralDirectoryHeader(ZipEntry entry)
 1865    {
 1866      if (entry.CompressedSize < 0) {
 1867        throw new ZipException("Attempt to write central directory entry with unknown csize");
 1868      }
 1869
 1870      if (entry.Size < 0) {
 1871        throw new ZipException("Attempt to write central directory entry with unknown size");
 1872      }
 1873
 1874      if (entry.Crc < 0) {
 1875        throw new ZipException("Attempt to write central directory entry with unknown crc");
 1876      }
 1877
 1878      // Write the central file header
 1879      WriteLEInt(ZipConstants.CentralHeaderSignature);
 1880
 1881      // Version made by
 1882      WriteLEShort(ZipConstants.VersionMadeBy);
 1883
 1884      // Version required to extract
 1885      WriteLEShort(entry.Version);
 1886
 1887      WriteLEShort(entry.Flags);
 1888
 1889      unchecked {
 1890        WriteLEShort((byte)entry.CompressionMethod);
 1891        WriteLEInt((int)entry.DosTime);
 1892        WriteLEInt((int)entry.Crc);
 1893      }
 1894
 1895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {
 1896        WriteLEInt(-1);
 1897      } else {
 1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
 1899      }
 1900
 1901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {
 1902        WriteLEInt(-1);
 1903      } else {
 1904        WriteLEInt((int)entry.Size);
 1905      }
 1906
 1907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1908
 1909      if (name.Length > 0xFFFF) {
 1910        throw new ZipException("Entry name is too long.");
 1911      }
 1912
 1913      WriteLEShort(name.Length);
 1914
 1915      // Central header extra data is different to local header version so regenerate.
 1916      var ed = new ZipExtraData(entry.ExtraData);
 1917
 1918      if (entry.CentralHeaderRequiresZip64) {
 1919        ed.StartNewEntry();
 1920
 1921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1922          ed.AddLeLong(entry.Size);
 1923        }
 1924
 1925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1926          ed.AddLeLong(entry.CompressedSize);
 1927        }
 1928
 1929        if (entry.Offset >= 0xffffffff) {
 1930          ed.AddLeLong(entry.Offset);
 1931        }
 1932
 1933        // Number of disk on which this file starts isnt supported and is never written here.
 1934        ed.AddNewEntry(1);
 1935      } else {
 1936        // Should have already be done when local header was added.
 1937        ed.Delete(1);
 1938      }
 1939
 1940      byte[] centralExtraData = ed.GetEntryData();
 1941
 1942      WriteLEShort(centralExtraData.Length);
 1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);
 1944
 1945      WriteLEShort(0);    // disk number
 1946      WriteLEShort(0);    // internal file attributes
 1947
 1948      // External file attributes...
 1949      if (entry.ExternalFileAttributes != -1) {
 1950        WriteLEInt(entry.ExternalFileAttributes);
 1951      } else {
 1952        if (entry.IsDirectory) {
 1953          WriteLEUint(16);
 1954        } else {
 1955          WriteLEUint(0);
 1956        }
 1957      }
 1958
 1959      if (entry.Offset >= 0xffffffff) {
 1960        WriteLEUint(0xffffffff);
 1961      } else {
 1962        WriteLEUint((uint)(int)entry.Offset);
 1963      }
 1964
 1965      if (name.Length > 0) {
 1966        baseStream_.Write(name, 0, name.Length);
 1967      }
 1968
 1969      if (centralExtraData.Length > 0) {
 1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
 1971      }
 1972
 1973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];
 1974
 1975      if (rawComment.Length > 0) {
 1976        baseStream_.Write(rawComment, 0, rawComment.Length);
 1977      }
 1978
 1979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
 1980    }
 1981    #endregion
 1982
 1983    void PostUpdateCleanup()
 1984    {
 1985      updateDataSource_ = null;
 1986      updates_ = null;
 1987      updateIndex_ = null;
 1988
 1989      if (archiveStorage_ != null) {
 1990        archiveStorage_.Dispose();
 1991        archiveStorage_ = null;
 1992      }
 1993    }
 1994
 1995    string GetTransformedFileName(string name)
 1996    {
 1997      INameTransform transform = NameTransform;
 1998      return (transform != null) ?
 1999        transform.TransformFile(name) :
 2000        name;
 2001    }
 2002
 2003    string GetTransformedDirectoryName(string name)
 2004    {
 2005      INameTransform transform = NameTransform;
 2006      return (transform != null) ?
 2007        transform.TransformDirectory(name) :
 2008        name;
 2009    }
 2010
 2011    /// <summary>
 2012    /// Get a raw memory buffer.
 2013    /// </summary>
 2014    /// <returns>Returns a raw memory buffer.</returns>
 2015    byte[] GetBuffer()
 2016    {
 2017      if (copyBuffer_ == null) {
 2018        copyBuffer_ = new byte[bufferSize_];
 2019      }
 2020      return copyBuffer_;
 2021    }
 2022
 2023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)
 2024    {
 2025      int bytesToCopy = GetDescriptorSize(update);
 2026
 2027      if (bytesToCopy > 0) {
 2028        byte[] buffer = GetBuffer();
 2029
 2030        while (bytesToCopy > 0) {
 2031          int readSize = Math.Min(buffer.Length, bytesToCopy);
 2032
 2033          int bytesRead = source.Read(buffer, 0, readSize);
 2034          if (bytesRead > 0) {
 2035            dest.Write(buffer, 0, bytesRead);
 2036            bytesToCopy -= bytesRead;
 2037          } else {
 2038            throw new ZipException("Unxpected end of stream");
 2039          }
 2040        }
 2041      }
 2042    }
 2043
 2044    void CopyBytes(ZipUpdate update, Stream destination, Stream source,
 2045      long bytesToCopy, bool updateCrc)
 2046    {
 2047      if (destination == source) {
 2048        throw new InvalidOperationException("Destination and source are the same");
 2049      }
 2050
 2051      // NOTE: Compressed size is updated elsewhere.
 2052      var crc = new Crc32();
 2053      byte[] buffer = GetBuffer();
 2054
 2055      long targetBytes = bytesToCopy;
 2056      long totalBytesRead = 0;
 2057
 2058      int bytesRead;
 2059      do {
 2060        int readSize = buffer.Length;
 2061
 2062        if (bytesToCopy < readSize) {
 2063          readSize = (int)bytesToCopy;
 2064        }
 2065
 2066        bytesRead = source.Read(buffer, 0, readSize);
 2067        if (bytesRead > 0) {
 2068          if (updateCrc) {
 2069            crc.Update(buffer, 0, bytesRead);
 2070          }
 2071          destination.Write(buffer, 0, bytesRead);
 2072          bytesToCopy -= bytesRead;
 2073          totalBytesRead += bytesRead;
 2074        }
 2075      }
 2076      while ((bytesRead > 0) && (bytesToCopy > 0));
 2077
 2078      if (totalBytesRead != targetBytes) {
 2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2080      }
 2081
 2082      if (updateCrc) {
 2083        update.OutEntry.Crc = crc.Value;
 2084      }
 2085    }
 2086
 2087    /// <summary>
 2088    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
 2089    /// </summary>
 2090    /// <param name="update">The update to get the size for.</param>
 2091    /// <returns>The descriptor size, zero if there isnt one.</returns>
 2092    int GetDescriptorSize(ZipUpdate update)
 2093    {
 2094      int result = 0;
 2095      if ((update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 2096        result = ZipConstants.DataDescriptorSize - 4;
 2097        if (update.Entry.LocalHeaderRequiresZip64) {
 2098          result = ZipConstants.Zip64DataDescriptorSize - 4;
 2099        }
 2100      }
 2101      return result;
 2102    }
 2103
 2104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
 2105    {
 2106      int bytesToCopy = GetDescriptorSize(update);
 2107
 2108      while (bytesToCopy > 0) {
 2109        var readSize = (int)bytesToCopy;
 2110        byte[] buffer = GetBuffer();
 2111
 2112        stream.Position = sourcePosition;
 2113        int bytesRead = stream.Read(buffer, 0, readSize);
 2114        if (bytesRead > 0) {
 2115          stream.Position = destinationPosition;
 2116          stream.Write(buffer, 0, bytesRead);
 2117          bytesToCopy -= bytesRead;
 2118          destinationPosition += bytesRead;
 2119          sourcePosition += bytesRead;
 2120        } else {
 2121          throw new ZipException("Unxpected end of stream");
 2122        }
 2123      }
 2124    }
 2125
 2126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou
 2127    {
 2128      long bytesToCopy = update.Entry.CompressedSize;
 2129
 2130      // NOTE: Compressed size is updated elsewhere.
 2131      var crc = new Crc32();
 2132      byte[] buffer = GetBuffer();
 2133
 2134      long targetBytes = bytesToCopy;
 2135      long totalBytesRead = 0;
 2136
 2137      int bytesRead;
 2138      do {
 2139        int readSize = buffer.Length;
 2140
 2141        if (bytesToCopy < readSize) {
 2142          readSize = (int)bytesToCopy;
 2143        }
 2144
 2145        stream.Position = sourcePosition;
 2146        bytesRead = stream.Read(buffer, 0, readSize);
 2147        if (bytesRead > 0) {
 2148          if (updateCrc) {
 2149            crc.Update(buffer, 0, bytesRead);
 2150          }
 2151          stream.Position = destinationPosition;
 2152          stream.Write(buffer, 0, bytesRead);
 2153
 2154          destinationPosition += bytesRead;
 2155          sourcePosition += bytesRead;
 2156          bytesToCopy -= bytesRead;
 2157          totalBytesRead += bytesRead;
 2158        }
 2159      }
 2160      while ((bytesRead > 0) && (bytesToCopy > 0));
 2161
 2162      if (totalBytesRead != targetBytes) {
 2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2164      }
 2165
 2166      if (updateCrc) {
 2167        update.OutEntry.Crc = crc.Value;
 2168      }
 2169    }
 2170
 2171    int FindExistingUpdate(ZipEntry entry)
 2172    {
 2173      int result = -1;
 2174      string convertedName = GetTransformedFileName(entry.Name);
 2175
 2176      if (updateIndex_.ContainsKey(convertedName)) {
 2177        result = (int)updateIndex_[convertedName];
 2178      }
 2179      /*
 2180            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2181            // for CF?
 2182            for (int index = 0; index < updates_.Count; ++index)
 2183            {
 2184              ZipUpdate zu = ( ZipUpdate )updates_[index];
 2185              if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
 2186                (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
 2187                result = index;
 2188                break;
 2189              }
 2190            }
 2191       */
 2192      return result;
 2193    }
 2194
 2195    int FindExistingUpdate(string fileName)
 2196    {
 2197      int result = -1;
 2198
 2199      string convertedName = GetTransformedFileName(fileName);
 2200
 2201      if (updateIndex_.ContainsKey(convertedName)) {
 2202        result = (int)updateIndex_[convertedName];
 2203      }
 2204
 2205      /*
 2206            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2207            // for CF?
 2208            for ( int index = 0; index < updates_.Count; ++index ) {
 2209              if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,
 2210                true, CultureInfo.InvariantCulture) == 0 ) {
 2211                result = index;
 2212                break;
 2213              }
 2214            }
 2215       */
 2216
 2217      return result;
 2218    }
 2219
 2220    /// <summary>
 2221    /// Get an output stream for the specified <see cref="ZipEntry"/>
 2222    /// </summary>
 2223    /// <param name="entry">The entry to get an output stream for.</param>
 2224    /// <returns>The output stream obtained for the entry.</returns>
 2225    Stream GetOutputStream(ZipEntry entry)
 2226    {
 2227      Stream result = baseStream_;
 2228
 2229      if (entry.IsCrypted == true) {
 2230        result = CreateAndInitEncryptionStream(result, entry);
 2231      }
 2232
 2233      switch (entry.CompressionMethod) {
 2234        case CompressionMethod.Stored:
 2235          result = new UncompressedStream(result);
 2236          break;
 2237
 2238        case CompressionMethod.Deflated:
 2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));
 2240          dos.IsStreamOwner = false;
 2241          result = dos;
 2242          break;
 2243
 2244        default:
 2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);
 2246      }
 2247      return result;
 2248    }
 2249
 2250    void AddEntry(ZipFile workFile, ZipUpdate update)
 2251    {
 2252      Stream source = null;
 2253
 2254      if (update.Entry.IsFile) {
 2255        source = update.GetSource();
 2256
 2257        if (source == null) {
 2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);
 2259        }
 2260      }
 2261
 2262      if (source != null) {
 2263        using (source) {
 2264          long sourceStreamLength = source.Length;
 2265          if (update.OutEntry.Size < 0) {
 2266            update.OutEntry.Size = sourceStreamLength;
 2267          } else {
 2268            // Check for errant entries.
 2269            if (update.OutEntry.Size != sourceStreamLength) {
 2270              throw new ZipException("Entry size/stream size mismatch");
 2271            }
 2272          }
 2273
 2274          workFile.WriteLocalEntryHeader(update);
 2275
 2276          long dataStart = workFile.baseStream_.Position;
 2277
 2278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2279            CopyBytes(update, output, source, sourceStreamLength, true);
 2280          }
 2281
 2282          long dataEnd = workFile.baseStream_.Position;
 2283          update.OutEntry.CompressedSize = dataEnd - dataStart;
 2284
 2285          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor) {
 2286            var helper = new ZipHelperStream(workFile.baseStream_);
 2287            helper.WriteDataDescriptor(update.OutEntry);
 2288          }
 2289        }
 2290      } else {
 2291        workFile.WriteLocalEntryHeader(update);
 2292        update.OutEntry.CompressedSize = 0;
 2293      }
 2294
 2295    }
 2296
 2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)
 2298    {
 2299      workFile.WriteLocalEntryHeader(update);
 2300      long dataStart = workFile.baseStream_.Position;
 2301
 2302      // TODO: This is slow if the changes don't effect the data!!
 2303      if (update.Entry.IsFile && (update.Filename != null)) {
 2304        using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2305          using (Stream source = this.GetInputStream(update.Entry)) {
 2306            CopyBytes(update, output, source, source.Length, true);
 2307          }
 2308        }
 2309      }
 2310
 2311      long dataEnd = workFile.baseStream_.Position;
 2312      update.Entry.CompressedSize = dataEnd - dataStart;
 2313    }
 2314
 2315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)
 2316    {
 2317      bool skipOver = false || update.Entry.Offset == destinationPosition;
 2318
 2319      if (!skipOver) {
 2320        baseStream_.Position = destinationPosition;
 2321        workFile.WriteLocalEntryHeader(update);
 2322        destinationPosition = baseStream_.Position;
 2323      }
 2324
 2325      long sourcePosition = 0;
 2326
 2327      const int NameLengthOffset = 26;
 2328
 2329      // TODO: Add base for SFX friendly handling
 2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2331
 2332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2333
 2334      // Clumsy way of handling retrieving the original name and extra data length for now.
 2335      // TODO: Stop re-reading name and data length in CopyEntryDirect.
 2336      uint nameLength = ReadLEUshort();
 2337      uint extraLength = ReadLEUshort();
 2338
 2339      sourcePosition = baseStream_.Position + nameLength + extraLength;
 2340
 2341      if (skipOver) {
 2342        if (update.OffsetBasedSize != -1)
 2343          destinationPosition += update.OffsetBasedSize;
 2344        else
 2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar
 2346          // WinZip produces a warning on these entries:
 2347          // "caution: value of lrec.csize (compressed size) changed from ..."
 2348          destinationPosition +=
 2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size
 2350            update.Entry.CompressedSize + GetDescriptorSize(update);
 2351      } else {
 2352        if (update.Entry.CompressedSize > 0) {
 2353          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition);
 2354        }
 2355        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
 2356      }
 2357    }
 2358
 2359    void CopyEntry(ZipFile workFile, ZipUpdate update)
 2360    {
 2361      workFile.WriteLocalEntryHeader(update);
 2362
 2363      if (update.Entry.CompressedSize > 0) {
 2364        const int NameLengthOffset = 26;
 2365
 2366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2367
 2368        // TODO: This wont work for SFX files!
 2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2370
 2371        uint nameLength = ReadLEUshort();
 2372        uint extraLength = ReadLEUshort();
 2373
 2374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);
 2375
 2376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
 2377      }
 2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
 2379    }
 2380
 2381    void Reopen(Stream source)
 2382    {
 2383      if (source == null) {
 2384        throw new ZipException("Failed to reopen archive - no source");
 2385      }
 2386
 2387      isNewArchive_ = false;
 2388      baseStream_ = source;
 2389      ReadEntries();
 2390    }
 2391
 2392    void Reopen()
 2393    {
 2394      if (Name == null) {
 2395        throw new InvalidOperationException("Name is not known cannot Reopen");
 2396      }
 2397
 2398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));
 2399    }
 2400
 2401    void UpdateCommentOnly()
 2402    {
 2403      long baseLength = baseStream_.Length;
 2404
 2405      ZipHelperStream updateFile = null;
 2406
 2407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
 2409        updateFile = new ZipHelperStream(copyStream);
 2410        updateFile.IsStreamOwner = true;
 2411
 2412        baseStream_.Close();
 2413        baseStream_ = null;
 2414      } else {
 2415        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2416          // TODO: archiveStorage wasnt originally intended for this use.
 2417          // Need to revisit this to tidy up handling as archive storage currently doesnt
 2418          // handle the original stream well.
 2419          // The problem is when using an existing zip archive with an in memory archive storage.
 2420          // The open stream wont support writing but the memory storage should open the same file not an in memory one.
 2421
 2422          // Need to tidy up the archive storage interface and contract basically.
 2423          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);
 2424          updateFile = new ZipHelperStream(baseStream_);
 2425        } else {
 2426          baseStream_.Close();
 2427          baseStream_ = null;
 2428          updateFile = new ZipHelperStream(Name);
 2429        }
 2430      }
 2431
 2432      using (updateFile) {
 2433        long locatedCentralDirOffset =
 2434          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2435                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2436        if (locatedCentralDirOffset < 0) {
 2437          throw new ZipException("Cannot find central directory");
 2438        }
 2439
 2440        const int CentralHeaderCommentSizeOffset = 16;
 2441        updateFile.Position += CentralHeaderCommentSizeOffset;
 2442
 2443        byte[] rawComment = newComment_.RawComment;
 2444
 2445        updateFile.WriteLEShort(rawComment.Length);
 2446        updateFile.Write(rawComment, 0, rawComment.Length);
 2447        updateFile.SetLength(updateFile.Position);
 2448      }
 2449
 2450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2452      } else {
 2453        ReadEntries();
 2454      }
 2455    }
 2456
 2457    /// <summary>
 2458    /// Class used to sort updates.
 2459    /// </summary>
 2460    class UpdateComparer : IComparer
 2461    {
 2462      /// <summary>
 2463      /// Compares two objects and returns a value indicating whether one is
 2464      /// less than, equal to or greater than the other.
 2465      /// </summary>
 2466      /// <param name="x">First object to compare</param>
 2467      /// <param name="y">Second object to compare.</param>
 2468      /// <returns>Compare result.</returns>
 2469      public int Compare(
 2470        object x,
 2471        object y)
 2472      {
 2473        var zx = x as ZipUpdate;
 2474        var zy = y as ZipUpdate;
 2475
 2476        int result;
 2477
 2478        if (zx == null) {
 2479          if (zy == null) {
 2480            result = 0;
 2481          } else {
 2482            result = -1;
 2483          }
 2484        } else if (zy == null) {
 2485          result = 1;
 2486        } else {
 2487          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;
 2488          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;
 2489
 2490          result = xCmdValue - yCmdValue;
 2491          if (result == 0) {
 2492            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;
 2493            if (offsetDiff < 0) {
 2494              result = -1;
 2495            } else if (offsetDiff == 0) {
 2496              result = 0;
 2497            } else {
 2498              result = 1;
 2499            }
 2500          }
 2501        }
 2502        return result;
 2503      }
 2504    }
 2505
 2506    void RunUpdates()
 2507    {
 2508      long sizeEntries = 0;
 2509      long endOfStream = 0;
 2510      bool directUpdate = false;
 2511      long destinationPosition = 0; // NOT SFX friendly
 2512
 2513      ZipFile workFile;
 2514
 2515      if (IsNewArchive) {
 2516        workFile = this;
 2517        workFile.baseStream_.Position = 0;
 2518        directUpdate = true;
 2519      } else if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2520        workFile = this;
 2521        workFile.baseStream_.Position = 0;
 2522        directUpdate = true;
 2523
 2524        // Sort the updates by offset within copies/modifies, then adds.
 2525        // This ensures that data required by copies will not be overwritten.
 2526        updates_.Sort(new UpdateComparer());
 2527      } else {
 2528        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
 2529        workFile.UseZip64 = UseZip64;
 2530
 2531        if (key != null) {
 2532          workFile.key = (byte[])key.Clone();
 2533        }
 2534      }
 2535
 2536      try {
 2537        foreach (ZipUpdate update in updates_) {
 2538          if (update != null) {
 2539            switch (update.Command) {
 2540              case UpdateCommand.Copy:
 2541                if (directUpdate) {
 2542                  CopyEntryDirect(workFile, update, ref destinationPosition);
 2543                } else {
 2544                  CopyEntry(workFile, update);
 2545                }
 2546                break;
 2547
 2548              case UpdateCommand.Modify:
 2549                // TODO: Direct modifying of an entry will take some legwork.
 2550                ModifyEntry(workFile, update);
 2551                break;
 2552
 2553              case UpdateCommand.Add:
 2554                if (!IsNewArchive && directUpdate) {
 2555                  workFile.baseStream_.Position = destinationPosition;
 2556                }
 2557
 2558                AddEntry(workFile, update);
 2559
 2560                if (directUpdate) {
 2561                  destinationPosition = workFile.baseStream_.Position;
 2562                }
 2563                break;
 2564            }
 2565          }
 2566        }
 2567
 2568        if (!IsNewArchive && directUpdate) {
 2569          workFile.baseStream_.Position = destinationPosition;
 2570        }
 2571
 2572        long centralDirOffset = workFile.baseStream_.Position;
 2573
 2574        foreach (ZipUpdate update in updates_) {
 2575          if (update != null) {
 2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
 2577          }
 2578        }
 2579
 2580        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 2581        using (ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_)) {
 2582          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);
 2583        }
 2584
 2585        endOfStream = workFile.baseStream_.Position;
 2586
 2587        // And now patch entries...
 2588        foreach (ZipUpdate update in updates_) {
 2589          if (update != null) {
 2590            // If the size of the entry is zero leave the crc as 0 as well.
 2591            // The calculated crc will be all bits on...
 2592            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {
 2593              workFile.baseStream_.Position = update.CrcPatchOffset;
 2594              workFile.WriteLEInt((int)update.OutEntry.Crc);
 2595            }
 2596
 2597            if (update.SizePatchOffset > 0) {
 2598              workFile.baseStream_.Position = update.SizePatchOffset;
 2599              if (update.OutEntry.LocalHeaderRequiresZip64) {
 2600                workFile.WriteLeLong(update.OutEntry.Size);
 2601                workFile.WriteLeLong(update.OutEntry.CompressedSize);
 2602              } else {
 2603                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);
 2604                workFile.WriteLEInt((int)update.OutEntry.Size);
 2605              }
 2606            }
 2607          }
 2608        }
 2609      } catch {
 2610        workFile.Close();
 2611        if (!directUpdate && (workFile.Name != null)) {
 2612          File.Delete(workFile.Name);
 2613        }
 2614        throw;
 2615      }
 2616
 2617      if (directUpdate) {
 2618        workFile.baseStream_.SetLength(endOfStream);
 2619        workFile.baseStream_.Flush();
 2620        isNewArchive_ = false;
 2621        ReadEntries();
 2622      } else {
 2623        baseStream_.Close();
 2624        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2625      }
 2626    }
 2627
 2628    void CheckUpdating()
 2629    {
 2630      if (updates_ == null) {
 2631        throw new InvalidOperationException("BeginUpdate has not been called");
 2632      }
 2633    }
 2634
 2635    #endregion
 2636
 2637    #region ZipUpdate class
 2638    /// <summary>
 2639    /// Represents a pending update to a Zip file.
 2640    /// </summary>
 2641    class ZipUpdate
 2642    {
 2643      #region Constructors
 2644      public ZipUpdate(string fileName, ZipEntry entry)
 2645      {
 2646        command_ = UpdateCommand.Add;
 2647        entry_ = entry;
 2648        filename_ = fileName;
 2649      }
 2650
 2651      [Obsolete]
 2652      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 2653      {
 2654        command_ = UpdateCommand.Add;
 2655        entry_ = new ZipEntry(entryName);
 2656        entry_.CompressionMethod = compressionMethod;
 2657        filename_ = fileName;
 2658      }
 2659
 2660      [Obsolete]
 2661      public ZipUpdate(string fileName, string entryName)
 2662        : this(fileName, entryName, CompressionMethod.Deflated)
 2663      {
 2664        // Do nothing.
 2665      }
 2666
 2667      [Obsolete]
 2668      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 2669      {
 2670        command_ = UpdateCommand.Add;
 2671        entry_ = new ZipEntry(entryName);
 2672        entry_.CompressionMethod = compressionMethod;
 2673        dataSource_ = dataSource;
 2674      }
 2675
 2676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 2677      {
 2678        command_ = UpdateCommand.Add;
 2679        entry_ = entry;
 2680        dataSource_ = dataSource;
 2681      }
 2682
 2683      public ZipUpdate(ZipEntry original, ZipEntry updated)
 2684      {
 2685        throw new ZipException("Modify not currently supported");
 2686        /*
 2687          command_ = UpdateCommand.Modify;
 2688          entry_ = ( ZipEntry )original.Clone();
 2689          outEntry_ = ( ZipEntry )updated.Clone();
 2690        */
 2691      }
 2692
 2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)
 2694      {
 2695        command_ = command;
 2696        entry_ = (ZipEntry)entry.Clone();
 2697      }
 2698
 2699
 2700      /// <summary>
 2701      /// Copy an existing entry.
 2702      /// </summary>
 2703      /// <param name="entry">The existing entry to copy.</param>
 2704      public ZipUpdate(ZipEntry entry)
 2705        : this(UpdateCommand.Copy, entry)
 2706      {
 2707        // Do nothing.
 2708      }
 2709      #endregion
 2710
 2711      /// <summary>
 2712      /// Get the <see cref="ZipEntry"/> for this update.
 2713      /// </summary>
 2714      /// <remarks>This is the source or original entry.</remarks>
 2715      public ZipEntry Entry {
 2716        get { return entry_; }
 2717      }
 2718
 2719      /// <summary>
 2720      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.
 2721      /// </summary>
 2722      public ZipEntry OutEntry {
 2723        get {
 2724          if (outEntry_ == null) {
 2725            outEntry_ = (ZipEntry)entry_.Clone();
 2726          }
 2727
 2728          return outEntry_;
 2729        }
 2730      }
 2731
 2732      /// <summary>
 2733      /// Get the command for this update.
 2734      /// </summary>
 2735      public UpdateCommand Command {
 2736        get { return command_; }
 2737      }
 2738
 2739      /// <summary>
 2740      /// Get the filename if any for this update.  Null if none exists.
 2741      /// </summary>
 2742      public string Filename {
 2743        get { return filename_; }
 2744      }
 2745
 2746      /// <summary>
 2747      /// Get/set the location of the size patch for this update.
 2748      /// </summary>
 2749      public long SizePatchOffset {
 2750        get { return sizePatchOffset_; }
 2751        set { sizePatchOffset_ = value; }
 2752      }
 2753
 2754      /// <summary>
 2755      /// Get /set the location of the crc patch for this update.
 2756      /// </summary>
 2757      public long CrcPatchOffset {
 2758        get { return crcPatchOffset_; }
 2759        set { crcPatchOffset_ = value; }
 2760      }
 2761
 2762      /// <summary>
 2763      /// Get/set the size calculated by offset.
 2764      /// Specifically, the difference between this and next entry's starting offset.
 2765      /// </summary>
 2766      public long OffsetBasedSize {
 2767        get { return _offsetBasedSize; }
 2768        set { _offsetBasedSize = value; }
 2769      }
 2770
 2771      public Stream GetSource()
 2772      {
 2773        Stream result = null;
 2774        if (dataSource_ != null) {
 2775          result = dataSource_.GetSource();
 2776        }
 2777
 2778        return result;
 2779      }
 2780
 2781      #region Instance Fields
 2782      ZipEntry entry_;
 2783      ZipEntry outEntry_;
 2784      UpdateCommand command_;
 2785      IStaticDataSource dataSource_;
 2786      string filename_;
 2787      long sizePatchOffset_ = -1;
 2788      long crcPatchOffset_ = -1;
 2789      long _offsetBasedSize = -1;
 2790      #endregion
 2791    }
 2792
 2793    #endregion
 2794    #endregion
 2795
 2796    #region Disposing
 2797
 2798    #region IDisposable Members
 2799    void IDisposable.Dispose()
 2800    {
 2801      Close();
 2802    }
 2803    #endregion
 2804
 2805    void DisposeInternal(bool disposing)
 2806    {
 2807      if (!isDisposed_) {
 2808        isDisposed_ = true;
 2809        entries_ = new ZipEntry[0];
 2810
 2811        if (IsStreamOwner && (baseStream_ != null)) {
 2812          lock (baseStream_) {
 2813            baseStream_.Close();
 2814          }
 2815        }
 2816
 2817        PostUpdateCleanup();
 2818      }
 2819    }
 2820
 2821    /// <summary>
 2822    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.
 2823    /// </summary>
 2824    /// <param name="disposing">true to release both managed and unmanaged resources;
 2825    /// false to release only unmanaged resources.</param>
 2826    protected virtual void Dispose(bool disposing)
 2827    {
 2828      DisposeInternal(disposing);
 2829    }
 2830
 2831    #endregion
 2832
 2833    #region Internal routines
 2834    #region Reading
 2835    /// <summary>
 2836    /// Read an unsigned short in little endian byte order.
 2837    /// </summary>
 2838    /// <returns>Returns the value read.</returns>
 2839    /// <exception cref="EndOfStreamException">
 2840    /// The stream ends prematurely
 2841    /// </exception>
 2842    ushort ReadLEUshort()
 2843    {
 2844      int data1 = baseStream_.ReadByte();
 2845
 2846      if (data1 < 0) {
 2847        throw new EndOfStreamException("End of stream");
 2848      }
 2849
 2850      int data2 = baseStream_.ReadByte();
 2851
 2852      if (data2 < 0) {
 2853        throw new EndOfStreamException("End of stream");
 2854      }
 2855
 2856
 2857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));
 2858    }
 2859
 2860    /// <summary>
 2861    /// Read a uint in little endian byte order.
 2862    /// </summary>
 2863    /// <returns>Returns the value read.</returns>
 2864    /// <exception cref="IOException">
 2865    /// An i/o error occurs.
 2866    /// </exception>
 2867    /// <exception cref="System.IO.EndOfStreamException">
 2868    /// The file ends prematurely
 2869    /// </exception>
 2870    uint ReadLEUint()
 2871    {
 2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));
 2873    }
 2874
 2875    ulong ReadLEUlong()
 2876    {
 2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);
 2878    }
 2879
 2880    #endregion
 2881    // NOTE this returns the offset of the first byte after the signature.
 2882    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 2883    {
 2884      using (ZipHelperStream les = new ZipHelperStream(baseStream_)) {
 2885        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
 2886      }
 2887    }
 2888
 2889    /// <summary>
 2890    /// Search for and read the central directory of a zip file filling the entries array.
 2891    /// </summary>
 2892    /// <exception cref="System.IO.IOException">
 2893    /// An i/o error occurs.
 2894    /// </exception>
 2895    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 2896    /// The central directory is malformed or cannot be found
 2897    /// </exception>
 2898    void ReadEntries()
 2899    {
 2900      // Search for the End Of Central Directory.  When a zip comment is
 2901      // present the directory will start earlier
 2902      //
 2903      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
 2904      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
 2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
 2906      // this could be invalid.
 2907      // Could also speed this up by reading memory in larger blocks.
 2908
 2909      if (baseStream_.CanSeek == false) {
 2910        throw new ZipException("ZipFile stream must be seekable");
 2911      }
 2912
 2913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2915
 2916      if (locatedEndOfCentralDir < 0) {
 2917        throw new ZipException("Cannot find central directory");
 2918      }
 2919
 2920      // Read end of central directory record
 2921      ushort thisDiskNumber = ReadLEUshort();
 2922      ushort startCentralDirDisk = ReadLEUshort();
 2923      ulong entriesForThisDisk = ReadLEUshort();
 2924      ulong entriesForWholeCentralDir = ReadLEUshort();
 2925      ulong centralDirSize = ReadLEUint();
 2926      long offsetOfCentralDir = ReadLEUint();
 2927      uint commentSize = ReadLEUshort();
 2928
 2929      if (commentSize > 0) {
 2930        byte[] comment = new byte[commentSize];
 2931
 2932        StreamUtils.ReadFully(baseStream_, comment);
 2933        comment_ = ZipConstants.ConvertToString(comment);
 2934      } else {
 2935        comment_ = string.Empty;
 2936      }
 2937
 2938      bool isZip64 = false;
 2939
 2940      // Check if zip64 header information is required.
 2941      if ((thisDiskNumber == 0xffff) ||
 2942        (startCentralDirDisk == 0xffff) ||
 2943        (entriesForThisDisk == 0xffff) ||
 2944        (entriesForWholeCentralDir == 0xffff) ||
 2945        (centralDirSize == 0xffffffff) ||
 2946        (offsetOfCentralDir == 0xffffffff)) {
 2947        isZip64 = true;
 2948
 2949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 
 2950        if (offset < 0) {
 2951          throw new ZipException("Cannot find Zip64 locator");
 2952        }
 2953
 2954        // number of the disk with the start of the zip64 end of central directory 4 bytes
 2955        // relative offset of the zip64 end of central directory record 8 bytes
 2956        // total number of disks 4 bytes
 2957        ReadLEUint(); // startDisk64 is not currently used
 2958        ulong offset64 = ReadLEUlong();
 2959        uint totalDisks = ReadLEUint();
 2960
 2961        baseStream_.Position = (long)offset64;
 2962        long sig64 = ReadLEUint();
 2963
 2964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {
 2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
 2966        }
 2967
 2968        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
 2969        ulong recordSize = ReadLEUlong();
 2970        int versionMadeBy = ReadLEUshort();
 2971        int versionToExtract = ReadLEUshort();
 2972        uint thisDisk = ReadLEUint();
 2973        uint centralDirDisk = ReadLEUint();
 2974        entriesForThisDisk = ReadLEUlong();
 2975        entriesForWholeCentralDir = ReadLEUlong();
 2976        centralDirSize = ReadLEUlong();
 2977        offsetOfCentralDir = (long)ReadLEUlong();
 2978
 2979        // NOTE: zip64 extensible data sector (variable size) is ignored.
 2980      }
 2981
 2982      entries_ = new ZipEntry[entriesForThisDisk];
 2983
 2984      // SFX/embedded support, find the offset of the first entry vis the start of the stream
 2985      // This applies to Zip files that are appended to the end of an SFX stub.
 2986      // Or are appended as a resource to an executable.
 2987      // Zip files created by some archivers have the offsets altered to reflect the true offsets
 2988      // and so dont require any adjustment here...
 2989      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
 2990      if (!isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize))) {
 2991        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
 2992        if (offsetOfFirstEntry <= 0) {
 2993          throw new ZipException("Invalid embedded zip archive");
 2994        }
 2995      }
 2996
 2997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
 2998
 2999      for (ulong i = 0; i < entriesForThisDisk; i++) {
 3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
 3001          throw new ZipException("Wrong Central Directory signature");
 3002        }
 3003
 3004        int versionMadeBy = ReadLEUshort();
 3005        int versionToExtract = ReadLEUshort();
 3006        int bitFlags = ReadLEUshort();
 3007        int method = ReadLEUshort();
 3008        uint dostime = ReadLEUint();
 3009        uint crc = ReadLEUint();
 3010        var csize = (long)ReadLEUint();
 3011        var size = (long)ReadLEUint();
 3012        int nameLen = ReadLEUshort();
 3013        int extraLen = ReadLEUshort();
 3014        int commentLen = ReadLEUshort();
 3015
 3016        int diskStartNo = ReadLEUshort();  // Not currently used
 3017        int internalAttributes = ReadLEUshort();  // Not currently used
 3018
 3019        uint externalAttributes = ReadLEUint();
 3020        long offset = ReadLEUint();
 3021
 3022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
 3023
 3024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
 3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);
 3026
 3027        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
 3028        entry.Crc = crc & 0xffffffffL;
 3029        entry.Size = size & 0xffffffffL;
 3030        entry.CompressedSize = csize & 0xffffffffL;
 3031        entry.Flags = bitFlags;
 3032        entry.DosTime = (uint)dostime;
 3033        entry.ZipFileIndex = (long)i;
 3034        entry.Offset = offset;
 3035        entry.ExternalFileAttributes = (int)externalAttributes;
 3036
 3037        if ((bitFlags & 8) == 0) {
 3038          entry.CryptoCheckValue = (byte)(crc >> 24);
 3039        } else {
 3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
 3041        }
 3042
 3043        if (extraLen > 0) {
 3044          byte[] extra = new byte[extraLen];
 3045          StreamUtils.ReadFully(baseStream_, extra);
 3046          entry.ExtraData = extra;
 3047        }
 3048
 3049        entry.ProcessExtraData(false);
 3050
 3051        if (commentLen > 0) {
 3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
 3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
 3054        }
 3055
 3056        entries_[i] = entry;
 3057      }
 3058    }
 3059
 3060    /// <summary>
 3061    /// Locate the data for a given entry.
 3062    /// </summary>
 3063    /// <returns>
 3064    /// The start offset of the data.
 3065    /// </returns>
 3066    /// <exception cref="System.IO.EndOfStreamException">
 3067    /// The stream ends prematurely
 3068    /// </exception>
 3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 3070    /// The local header signature is invalid, the entry and central header file name lengths are different
 3071    /// or the local and entry compression methods dont match
 3072    /// </exception>
 3073    long LocateEntry(ZipEntry entry)
 3074    {
 3075      return TestLocalHeader(entry, HeaderTest.Extract);
 3076    }
 3077
 3078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
 3079    {
 3080      CryptoStream result = null;
 3081
 3082      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3084        var classicManaged = new PkzipClassicManaged();
 3085
 3086        OnKeysRequired(entry.Name);
 3087        if (HaveKeys == false) {
 3088          throw new ZipException("No password available for encrypted stream");
 3089        }
 3090
 3091        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
 3092        CheckClassicPassword(result, entry);
 3093      } else {
 3094        if (entry.Version == ZipConstants.VERSION_AES) {
 3095          //
 3096          OnKeysRequired(entry.Name);
 3097          if (HaveKeys == false) {
 3098            throw new ZipException("No password available for AES encrypted stream");
 3099          }
 3100          int saltLen = entry.AESSaltLen;
 3101          byte[] saltBytes = new byte[saltLen];
 3102          int saltIn = baseStream.Read(saltBytes, 0, saltLen);
 3103          if (saltIn != saltLen)
 3104            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
 3105          //
 3106          byte[] pwdVerifyRead = new byte[2];
 3107          baseStream.Read(pwdVerifyRead, 0, 2);
 3108          int blockSize = entry.AESKeySize / 8;   // bits to bytes
 3109
 3110          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
 3111          byte[] pwdVerifyCalc = decryptor.PwdVerifier;
 3112          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
 3113            throw new ZipException("Invalid password for AES");
 3114          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
 3115        } else {
 3116          throw new ZipException("Decryption method not supported");
 3117        }
 3118      }
 3119
 3120      return result;
 3121    }
 3122
 3123    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
 3124    {
 3125      CryptoStream result = null;
 3126      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3127        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3128        var classicManaged = new PkzipClassicManaged();
 3129
 3130        OnKeysRequired(entry.Name);
 3131        if (HaveKeys == false) {
 3132          throw new ZipException("No password available for encrypted stream");
 3133        }
 3134
 3135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
 3136        // which doesnt do this.
 3137        result = new CryptoStream(new UncompressedStream(baseStream),
 3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
 3139
 3140        if ((entry.Crc < 0) || (entry.Flags & 8) != 0) {
 3141          WriteEncryptionHeader(result, entry.DosTime << 16);
 3142        } else {
 3143          WriteEncryptionHeader(result, entry.Crc);
 3144        }
 3145      }
 3146      return result;
 3147    }
 3148
 3149    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
 3150    {
 3151      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
 3152      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
 3153      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
 3154        throw new ZipException("Invalid password");
 3155      }
 3156    }
 3157
 3158    static void WriteEncryptionHeader(Stream stream, long crcValue)
 3159    {
 3160      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
 3161      var rnd = new Random();
 3162      rnd.NextBytes(cryptBuffer);
 3163      cryptBuffer[11] = (byte)(crcValue >> 24);
 3164      stream.Write(cryptBuffer, 0, cryptBuffer.Length);
 3165    }
 3166
 3167    #endregion
 3168
 3169    #region Instance Fields
 3170    bool isDisposed_;
 3171    string name_;
 3172    string comment_;
 3173    string rawPassword_;
 3174    Stream baseStream_;
 3175    bool isStreamOwner;
 3176    long offsetOfFirstEntry;
 3177    ZipEntry[] entries_;
 3178    byte[] key;
 3179    bool isNewArchive_;
 3180
 3181    // Default is dynamic which is not backwards compatible and can cause problems
 3182    // with XP's built in compression which cant read Zip64 archives.
 3183    // However it does avoid the situation were a large file is added and cannot be completed correctly.
 3184    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.
 3185    UseZip64 useZip64_ = UseZip64.Dynamic;
 3186
 3187    #region Zip Update Instance Fields
 3188    ArrayList updates_;
 3189    long updateCount_; // Count is managed manually as updates_ can contain nulls!
 3190    Hashtable updateIndex_;
 3191    IArchiveStorage archiveStorage_;
 3192    IDynamicDataSource updateDataSource_;
 3193    bool contentsEdited_;
 3194    int bufferSize_ = DefaultBufferSize;
 3195    byte[] copyBuffer_;
 3196    ZipString newComment_;
 3197    bool commentEdited_;
 3198    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();
 3199    #endregion
 3200    #endregion
 3201
 3202    #region Support Classes
 3203    /// <summary>
 3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.
 3205    /// </summary>
 3206    class ZipString
 3207    {
 3208      #region Constructors
 3209      /// <summary>
 3210      /// Initialise a <see cref="ZipString"/> with a string.
 3211      /// </summary>
 3212      /// <param name="comment">The textual string form.</param>
 3213      public ZipString(string comment)
 3214      {
 3215        comment_ = comment;
 3216        isSourceString_ = true;
 3217      }
 3218
 3219      /// <summary>
 3220      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.
 3221      /// </summary>
 3222      /// <param name="rawString"></param>
 3223      public ZipString(byte[] rawString)
 3224      {
 3225        rawComment_ = rawString;
 3226      }
 3227      #endregion
 3228
 3229      /// <summary>
 3230      /// Get a value indicating the original source of data for this instance.
 3231      /// True if the source was a string; false if the source was binary data.
 3232      /// </summary>
 3233      public bool IsSourceString {
 3234        get { return isSourceString_; }
 3235      }
 3236
 3237      /// <summary>
 3238      /// Get the length of the comment when represented as raw bytes.
 3239      /// </summary>
 3240      public int RawLength {
 3241        get {
 3242          MakeBytesAvailable();
 3243          return rawComment_.Length;
 3244        }
 3245      }
 3246
 3247      /// <summary>
 3248      /// Get the comment in its 'raw' form as plain bytes.
 3249      /// </summary>
 3250      public byte[] RawComment {
 3251        get {
 3252          MakeBytesAvailable();
 3253          return (byte[])rawComment_.Clone();
 3254        }
 3255      }
 3256
 3257      /// <summary>
 3258      /// Reset the comment to its initial state.
 3259      /// </summary>
 3260      public void Reset()
 3261      {
 3262        if (isSourceString_) {
 3263          rawComment_ = null;
 3264        } else {
 3265          comment_ = null;
 3266        }
 3267      }
 3268
 3269      void MakeTextAvailable()
 3270      {
 3271        if (comment_ == null) {
 3272          comment_ = ZipConstants.ConvertToString(rawComment_);
 3273        }
 3274      }
 3275
 3276      void MakeBytesAvailable()
 3277      {
 3278        if (rawComment_ == null) {
 3279          rawComment_ = ZipConstants.ConvertToArray(comment_);
 3280        }
 3281      }
 3282
 3283      /// <summary>
 3284      /// Implicit conversion of comment to a string.
 3285      /// </summary>
 3286      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>
 3287      /// <returns>The textual equivalent for the input value.</returns>
 3288      static public implicit operator string(ZipString zipString)
 3289      {
 3290        zipString.MakeTextAvailable();
 3291        return zipString.comment_;
 3292      }
 3293
 3294      #region Instance Fields
 3295      string comment_;
 3296      byte[] rawComment_;
 3297      bool isSourceString_;
 3298      #endregion
 3299    }
 3300
 3301    /// <summary>
 3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>
 3303    /// </summary>
 3304    class ZipEntryEnumerator : IEnumerator
 3305    {
 3306      #region Constructors
 3307      public ZipEntryEnumerator(ZipEntry[] entries)
 3308      {
 3309        array = entries;
 3310      }
 3311
 3312      #endregion
 3313      #region IEnumerator Members
 3314      public object Current {
 3315        get {
 3316          return array[index];
 3317        }
 3318      }
 3319
 3320      public void Reset()
 3321      {
 3322        index = -1;
 3323      }
 3324
 3325      public bool MoveNext()
 3326      {
 3327        return (++index < array.Length);
 3328      }
 3329      #endregion
 3330      #region Instance Fields
 3331      ZipEntry[] array;
 3332      int index = -1;
 3333      #endregion
 3334    }
 3335
 3336    /// <summary>
 3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data
 3338    /// to and flush, but cannot read, seek or do anything else to.
 3339    /// </summary>
 3340    class UncompressedStream : Stream
 3341    {
 3342      #region Constructors
 3343      public UncompressedStream(Stream baseStream)
 3344      {
 3345        baseStream_ = baseStream;
 3346      }
 3347
 3348      #endregion
 3349
 3350      /// <summary>
 3351      /// Close this stream instance.
 3352      /// </summary>
 3353      public override void Close()
 3354      {
 3355        // Do nothing
 3356      }
 3357
 3358      /// <summary>
 3359      /// Gets a value indicating whether the current stream supports reading.
 3360      /// </summary>
 3361      public override bool CanRead {
 3362        get {
 3363          return false;
 3364        }
 3365      }
 3366
 3367      /// <summary>
 3368      /// Write any buffered data to underlying storage.
 3369      /// </summary>
 3370      public override void Flush()
 3371      {
 3372        baseStream_.Flush();
 3373      }
 3374
 3375      /// <summary>
 3376      /// Gets a value indicating whether the current stream supports writing.
 3377      /// </summary>
 3378      public override bool CanWrite {
 3379        get {
 3380          return baseStream_.CanWrite;
 3381        }
 3382      }
 3383
 3384      /// <summary>
 3385      /// Gets a value indicating whether the current stream supports seeking.
 3386      /// </summary>
 3387      public override bool CanSeek {
 3388        get {
 3389          return false;
 3390        }
 3391      }
 3392
 3393      /// <summary>
 3394      /// Get the length in bytes of the stream.
 3395      /// </summary>
 3396      public override long Length {
 3397        get {
 3398          return 0;
 3399        }
 3400      }
 3401
 3402      /// <summary>
 3403      /// Gets or sets the position within the current stream.
 3404      /// </summary>
 3405      public override long Position {
 3406        get {
 3407          return baseStream_.Position;
 3408        }
 3409        set {
 3410          throw new NotImplementedException();
 3411        }
 3412      }
 3413
 3414      /// <summary>
 3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3416      /// </summary>
 3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3419      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3420      /// <returns>
 3421      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3422      /// </returns>
 3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3425      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3426      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3427      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3428      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3429      public override int Read(byte[] buffer, int offset, int count)
 3430      {
 3431        return 0;
 3432      }
 3433
 3434      /// <summary>
 3435      /// Sets the position within the current stream.
 3436      /// </summary>
 3437      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3438      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3439      /// <returns>
 3440      /// The new position within the current stream.
 3441      /// </returns>
 3442      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3443      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3445      public override long Seek(long offset, SeekOrigin origin)
 3446      {
 3447        return 0;
 3448      }
 3449
 3450      /// <summary>
 3451      /// Sets the length of the current stream.
 3452      /// </summary>
 3453      /// <param name="value">The desired length of the current stream in bytes.</param>
 3454      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3455      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3456      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3457      public override void SetLength(long value)
 3458      {
 3459      }
 3460
 3461      /// <summary>
 3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3463      /// </summary>
 3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3466      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3467      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3468      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3469      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3470      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3471      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3472      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3473      public override void Write(byte[] buffer, int offset, int count)
 3474      {
 3475        baseStream_.Write(buffer, offset, count);
 3476      }
 3477
 3478      readonly
 3479
 3480      #region Instance Fields
 3481      Stream baseStream_;
 3482      #endregion
 3483    }
 3484
 3485    /// <summary>
 3486    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>
 3487    /// whose data is only a part or subsection of a file.
 3488    /// </summary>
 3489    class PartialInputStream : Stream
 3490    {
 3491      #region Constructors
 3492      /// <summary>
 3493      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.
 3494      /// </summary>
 3495      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>
 3496      /// <param name="start">The start of the partial data.</param>
 3497      /// <param name="length">The length of the partial data.</param>
 3498      public PartialInputStream(ZipFile zipFile, long start, long length)
 3499      {
 3500        start_ = start;
 3501        length_ = length;
 3502
 3503        // Although this is the only time the zipfile is used
 3504        // keeping a reference here prevents premature closure of
 3505        // this zip file and thus the baseStream_.
 3506
 3507        // Code like this will cause apparently random failures depending
 3508        // on the size of the files and when garbage is collected.
 3509        //
 3510        // ZipFile z = new ZipFile (stream);
 3511        // Stream reader = z.GetInputStream(0);
 3512        // uses reader here....
 3513        zipFile_ = zipFile;
 3514        baseStream_ = zipFile_.baseStream_;
 3515        readPos_ = start;
 3516        end_ = start + length;
 3517      }
 3518      #endregion
 3519
 3520      /// <summary>
 3521      /// Read a byte from this stream.
 3522      /// </summary>
 3523      /// <returns>Returns the byte read or -1 on end of stream.</returns>
 3524      public override int ReadByte()
 3525      {
 3526        if (readPos_ >= end_) {
 3527          // -1 is the correct value at end of stream.
 3528          return -1;
 3529        }
 3530
 3531        lock (baseStream_) {
 3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);
 3533          return baseStream_.ReadByte();
 3534        }
 3535      }
 3536
 3537      /// <summary>
 3538      /// Close this <see cref="PartialInputStream">partial input stream</see>.
 3539      /// </summary>
 3540      /// <remarks>
 3541      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.
 3542      /// </remarks>
 3543      public override void Close()
 3544      {
 3545        // Do nothing at all!
 3546      }
 3547
 3548      /// <summary>
 3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3550      /// </summary>
 3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3553      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3554      /// <returns>
 3555      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3556      /// </returns>
 3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3559      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3560      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3561      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3562      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3563      public override int Read(byte[] buffer, int offset, int count)
 3564      {
 3565        lock (baseStream_) {
 3566          if (count > end_ - readPos_) {
 3567            count = (int)(end_ - readPos_);
 3568            if (count == 0) {
 3569              return 0;
 3570            }
 3571          }
 3572          // Protect against Stream implementations that throw away their buffer on every Seek
 3573          // (for example, Mono FileStream)
 3574          if (baseStream_.Position != readPos_) {
 3575            baseStream_.Seek(readPos_, SeekOrigin.Begin);
 3576          }
 3577          int readCount = baseStream_.Read(buffer, offset, count);
 3578          if (readCount > 0) {
 3579            readPos_ += readCount;
 3580          }
 3581          return readCount;
 3582        }
 3583      }
 3584
 3585      /// <summary>
 3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3587      /// </summary>
 3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3590      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3591      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3592      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3593      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3594      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3595      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3596      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3597      public override void Write(byte[] buffer, int offset, int count)
 3598      {
 3599        throw new NotSupportedException();
 3600      }
 3601
 3602      /// <summary>
 3603      /// When overridden in a derived class, sets the length of the current stream.
 3604      /// </summary>
 3605      /// <param name="value">The desired length of the current stream in bytes.</param>
 3606      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3607      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3608      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3609      public override void SetLength(long value)
 3610      {
 3611        throw new NotSupportedException();
 3612      }
 3613
 3614      /// <summary>
 3615      /// When overridden in a derived class, sets the position within the current stream.
 3616      /// </summary>
 3617      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3618      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3619      /// <returns>
 3620      /// The new position within the current stream.
 3621      /// </returns>
 3622      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3623      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3625      public override long Seek(long offset, SeekOrigin origin)
 3626      {
 3627        long newPos = readPos_;
 3628
 3629        switch (origin) {
 3630          case SeekOrigin.Begin:
 3631            newPos = start_ + offset;
 3632            break;
 3633
 3634          case SeekOrigin.Current:
 3635            newPos = readPos_ + offset;
 3636            break;
 3637
 3638          case SeekOrigin.End:
 3639            newPos = end_ + offset;
 3640            break;
 3641        }
 3642
 3643        if (newPos < start_) {
 3644          throw new ArgumentException("Negative position is invalid");
 3645        }
 3646
 3647        if (newPos >= end_) {
 3648          throw new IOException("Cannot seek past end");
 3649        }
 3650        readPos_ = newPos;
 3651        return readPos_;
 3652      }
 3653
 3654      /// <summary>
 3655      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
 3656      /// </summary>
 3657      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3658      public override void Flush()
 3659      {
 3660        // Nothing to do.
 3661      }
 3662
 3663      /// <summary>
 3664      /// Gets or sets the position within the current stream.
 3665      /// </summary>
 3666      /// <value></value>
 3667      /// <returns>The current position within the stream.</returns>
 3668      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3669      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>
 3670      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3671      public override long Position {
 3672        get { return readPos_ - start_; }
 3673        set {
 3674          long newPos = start_ + value;
 3675
 3676          if (newPos < start_) {
 3677            throw new ArgumentException("Negative position is invalid");
 3678          }
 3679
 3680          if (newPos >= end_) {
 3681            throw new InvalidOperationException("Cannot seek past end");
 3682          }
 3683          readPos_ = newPos;
 3684        }
 3685      }
 3686
 3687      /// <summary>
 3688      /// Gets the length in bytes of the stream.
 3689      /// </summary>
 3690      /// <value></value>
 3691      /// <returns>A long value representing the length of the stream in bytes.</returns>
 3692      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep
 3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3694      public override long Length {
 3695        get { return length_; }
 3696      }
 3697
 3698      /// <summary>
 3699      /// Gets a value indicating whether the current stream supports writing.
 3700      /// </summary>
 3701      /// <value>false</value>
 3702      /// <returns>true if the stream supports writing; otherwise, false.</returns>
 3703      public override bool CanWrite {
 3704        get { return false; }
 3705      }
 3706
 3707      /// <summary>
 3708      /// Gets a value indicating whether the current stream supports seeking.
 3709      /// </summary>
 3710      /// <value>true</value>
 3711      /// <returns>true if the stream supports seeking; otherwise, false.</returns>
 3712      public override bool CanSeek {
 3713        get { return true; }
 3714      }
 3715
 3716      /// <summary>
 3717      /// Gets a value indicating whether the current stream supports reading.
 3718      /// </summary>
 3719      /// <value>true.</value>
 3720      /// <returns>true if the stream supports reading; otherwise, false.</returns>
 3721      public override bool CanRead {
 3722        get { return true; }
 3723      }
 3724
 3725      /// <summary>
 3726      /// Gets a value that determines whether the current stream can time out.
 3727      /// </summary>
 3728      /// <value></value>
 3729      /// <returns>A value that determines whether the current stream can time out.</returns>
 3730      public override bool CanTimeout {
 3731        get { return baseStream_.CanTimeout; }
 3732      }
 3733      #region Instance Fields
 3734      ZipFile zipFile_;
 3735      Stream baseStream_;
 3736      long start_;
 3737      long length_;
 3738      long readPos_;
 3739      long end_;
 3740      #endregion
 3741    }
 3742    #endregion
 3743  }
 3744
 3745  #endregion
 3746
 3747  #region DataSources
 3748  /// <summary>
 3749  /// Provides a static way to obtain a source of data for an entry.
 3750  /// </summary>
 3751  public interface IStaticDataSource
 3752  {
 3753    /// <summary>
 3754    /// Get a source of data by creating a new stream.
 3755    /// </summary>
 3756    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3757    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3758    Stream GetSource();
 3759  }
 3760
 3761  /// <summary>
 3762  /// Represents a source of data that can dynamically provide
 3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.
 3764  /// </summary>
 3765  public interface IDynamicDataSource
 3766  {
 3767    /// <summary>
 3768    /// Get a data source.
 3769    /// </summary>
 3770    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>
 3771    /// <param name="name">The name for data if known.</param>
 3772    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3773    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3774    Stream GetSource(ZipEntry entry, string name);
 3775  }
 3776
 3777  /// <summary>
 3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.
 3779  /// </summary>
 3780  public class StaticDiskDataSource : IStaticDataSource
 3781  {
 3782    /// <summary>
 3783    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>
 3784    /// </summary>
 3785    /// <param name="fileName">The name of the file to obtain data from.</param>
 3786    public StaticDiskDataSource(string fileName)
 3787    {
 3788      fileName_ = fileName;
 3789    }
 3790
 3791    #region IDataSource Members
 3792
 3793    /// <summary>
 3794    /// Get a <see cref="Stream"/> providing data.
 3795    /// </summary>
 3796    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>
 3797    public Stream GetSource()
 3798    {
 3799      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 3800    }
 3801
 3802    readonly
 3803
 3804    #endregion
 3805    #region Instance Fields
 3806    string fileName_;
 3807    #endregion
 3808  }
 3809
 3810
 3811  /// <summary>
 3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.
 3813  /// </summary>
 3814  public class DynamicDiskDataSource : IDynamicDataSource
 3815  {
 3816
 3817    #region IDataSource Members
 3818    /// <summary>
 3819    /// Get a <see cref="Stream"/> providing data for an entry.
 3820    /// </summary>
 3821    /// <param name="entry">The entry to provide data for.</param>
 3822    /// <param name="name">The file name for data if known.</param>
 3823    /// <returns>Returns a stream providing data; or null if not available</returns>
 3824    public Stream GetSource(ZipEntry entry, string name)
 3825    {
 3826      Stream result = null;
 3827
 3828      if (name != null) {
 3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 3830      }
 3831
 3832      return result;
 3833    }
 3834
 3835    #endregion
 3836  }
 3837
 3838  #endregion
 3839
 3840  #region Archive Storage
 3841  /// <summary>
 3842  /// Defines facilities for data storage when updating Zip Archives.
 3843  /// </summary>
 3844  public interface IArchiveStorage
 3845  {
 3846    /// <summary>
 3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.
 3848    /// </summary>
 3849    FileUpdateMode UpdateMode { get; }
 3850
 3851    /// <summary>
 3852    /// Get an empty <see cref="Stream"/> that can be used for temporary output.
 3853    /// </summary>
 3854    /// <returns>Returns a temporary output <see cref="Stream"/></returns>
 3855    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3856    Stream GetTemporaryOutput();
 3857
 3858    /// <summary>
 3859    /// Convert a temporary output stream to a final stream.
 3860    /// </summary>
 3861    /// <returns>The resulting final <see cref="Stream"/></returns>
 3862    /// <seealso cref="GetTemporaryOutput"/>
 3863    Stream ConvertTemporaryToFinal();
 3864
 3865    /// <summary>
 3866    /// Make a temporary copy of the original stream.
 3867    /// </summary>
 3868    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 3869    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3870    Stream MakeTemporaryCopy(Stream stream);
 3871
 3872    /// <summary>
 3873    /// Return a stream suitable for performing direct updates on the original source.
 3874    /// </summary>
 3875    /// <param name="stream">The current stream.</param>
 3876    /// <returns>Returns a stream suitable for direct updating.</returns>
 3877    /// <remarks>This may be the current stream passed.</remarks>
 3878    Stream OpenForDirectUpdate(Stream stream);
 3879
 3880    /// <summary>
 3881    /// Dispose of this instance.
 3882    /// </summary>
 3883    void Dispose();
 3884  }
 3885
 3886  /// <summary>
 3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.
 3888  /// </summary>
 3889  abstract public class BaseArchiveStorage : IArchiveStorage
 3890  {
 3891    #region Constructors
 3892    /// <summary>
 3893    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.
 3894    /// </summary>
 3895    /// <param name="updateMode">The update mode.</param>
 3896    protected BaseArchiveStorage(FileUpdateMode updateMode)
 3897    {
 3898      updateMode_ = updateMode;
 3899    }
 3900    #endregion
 3901
 3902    #region IArchiveStorage Members
 3903
 3904    /// <summary>
 3905    /// Gets a temporary output <see cref="Stream"/>
 3906    /// </summary>
 3907    /// <returns>Returns the temporary output stream.</returns>
 3908    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3909    public abstract Stream GetTemporaryOutput();
 3910
 3911    /// <summary>
 3912    /// Converts the temporary <see cref="Stream"/> to its final form.
 3913    /// </summary>
 3914    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 3915    /// the final storage for the archive.</returns>
 3916    /// <seealso cref="GetTemporaryOutput"/>
 3917    public abstract Stream ConvertTemporaryToFinal();
 3918
 3919    /// <summary>
 3920    /// Make a temporary copy of a <see cref="Stream"/>.
 3921    /// </summary>
 3922    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>
 3923    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3924    public abstract Stream MakeTemporaryCopy(Stream stream);
 3925
 3926    /// <summary>
 3927    /// Return a stream suitable for performing direct updates on the original source.
 3928    /// </summary>
 3929    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>
 3930    /// <returns>Returns a stream suitable for direct updating.</returns>
 3931    public abstract Stream OpenForDirectUpdate(Stream stream);
 3932
 3933    /// <summary>
 3934    /// Disposes this instance.
 3935    /// </summary>
 3936    public abstract void Dispose();
 3937
 3938    /// <summary>
 3939    /// Gets the update mode applicable.
 3940    /// </summary>
 3941    /// <value>The update mode.</value>
 3942    public FileUpdateMode UpdateMode {
 3943      get {
 3944        return updateMode_;
 3945      }
 3946    }
 3947
 3948    #endregion
 3949
 3950    #region Instance Fields
 3951    FileUpdateMode updateMode_;
 3952    #endregion
 3953  }
 3954
 3955  /// <summary>
 3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.
 3957  /// </summary>
 3958  public class DiskArchiveStorage : BaseArchiveStorage
 3959  {
 3960    #region Constructors
 3961    /// <summary>
 3962    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3963    /// </summary>
 3964    /// <param name="file">The file.</param>
 3965    /// <param name="updateMode">The update mode.</param>
 3966    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)
 3967      : base(updateMode)
 3968    {
 3969      if (file.Name == null) {
 3970        throw new ZipException("Cant handle non file archives");
 3971      }
 3972
 3973      fileName_ = file.Name;
 3974    }
 3975
 3976    /// <summary>
 3977    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3978    /// </summary>
 3979    /// <param name="file">The file.</param>
 3980    public DiskArchiveStorage(ZipFile file)
 3981      : this(file, FileUpdateMode.Safe)
 3982    {
 3983    }
 3984    #endregion
 3985
 3986    #region IArchiveStorage Members
 3987
 3988    /// <summary>
 3989    /// Gets a temporary output <see cref="Stream"/> for performing updates on.
 3990    /// </summary>
 3991    /// <returns>Returns the temporary output stream.</returns>
 3992    public override Stream GetTemporaryOutput()
 3993    {
 3994      if (temporaryName_ != null) {
 3995        temporaryName_ = GetTempFileName(temporaryName_, true);
 3996        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 3997      } else {
 3998        // Determine where to place files based on internal strategy.
 3999        // Currently this is always done in system temp directory.
 4000        temporaryName_ = Path.GetTempFileName();
 4001        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 4002      }
 4003
 4004      return temporaryStream_;
 4005    }
 4006
 4007    /// <summary>
 4008    /// Converts a temporary <see cref="Stream"/> to its final form.
 4009    /// </summary>
 4010    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4011    /// the final storage for the archive.</returns>
 4012    public override Stream ConvertTemporaryToFinal()
 4013    {
 4014      if (temporaryStream_ == null) {
 4015        throw new ZipException("No temporary stream has been created");
 4016      }
 4017
 4018      Stream result = null;
 4019
 4020      string moveTempName = GetTempFileName(fileName_, false);
 4021      bool newFileCreated = false;
 4022
 4023      try {
 4024        temporaryStream_.Close();
 4025        File.Move(fileName_, moveTempName);
 4026        File.Move(temporaryName_, fileName_);
 4027        newFileCreated = true;
 4028        File.Delete(moveTempName);
 4029
 4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 4031      } catch (Exception) {
 4032        result = null;
 4033
 4034        // Try to roll back changes...
 4035        if (!newFileCreated) {
 4036          File.Move(moveTempName, fileName_);
 4037          File.Delete(temporaryName_);
 4038        }
 4039
 4040        throw;
 4041      }
 4042
 4043      return result;
 4044    }
 4045
 4046    /// <summary>
 4047    /// Make a temporary copy of a stream.
 4048    /// </summary>
 4049    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4050    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4051    public override Stream MakeTemporaryCopy(Stream stream)
 4052    {
 4053      stream.Close();
 4054
 4055      temporaryName_ = GetTempFileName(fileName_, true);
 4056      File.Copy(fileName_, temporaryName_, true);
 4057
 4058      temporaryStream_ = new FileStream(temporaryName_,
 4059        FileMode.Open,
 4060        FileAccess.ReadWrite);
 4061      return temporaryStream_;
 4062    }
 4063
 4064    /// <summary>
 4065    /// Return a stream suitable for performing direct updates on the original source.
 4066    /// </summary>
 4067    /// <param name="stream">The current stream.</param>
 4068    /// <returns>Returns a stream suitable for direct updating.</returns>
 4069    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>
 4070    public override Stream OpenForDirectUpdate(Stream stream)
 4071    {
 4072      Stream result;
 4073      if ((stream == null) || !stream.CanWrite) {
 4074        if (stream != null) {
 4075          stream.Close();
 4076        }
 4077
 4078        result = new FileStream(fileName_,
 4079            FileMode.Open,
 4080            FileAccess.ReadWrite);
 4081      } else {
 4082        result = stream;
 4083      }
 4084
 4085      return result;
 4086    }
 4087
 4088    /// <summary>
 4089    /// Disposes this instance.
 4090    /// </summary>
 4091    public override void Dispose()
 4092    {
 4093      if (temporaryStream_ != null) {
 4094        temporaryStream_.Close();
 4095      }
 4096    }
 4097
 4098    #endregion
 4099
 4100    #region Internal routines
 4101    static string GetTempFileName(string original, bool makeTempFile)
 4102    {
 4103      string result = null;
 4104
 4105      if (original == null) {
 4106        result = Path.GetTempFileName();
 4107      } else {
 4108        int counter = 0;
 4109        int suffixSeed = DateTime.Now.Second;
 4110
 4111        while (result == null) {
 4112          counter += 1;
 4113          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);
 4114          if (!File.Exists(newName)) {
 4115            if (makeTempFile) {
 4116              try {
 4117                // Try and create the file.
 4118                using (FileStream stream = File.Create(newName)) {
 4119                }
 4120                result = newName;
 4121              } catch {
 4122                suffixSeed = DateTime.Now.Second;
 4123              }
 4124            } else {
 4125              result = newName;
 4126            }
 4127          }
 4128        }
 4129      }
 4130      return result;
 4131    }
 4132    #endregion
 4133
 4134    #region Instance Fields
 4135    Stream temporaryStream_;
 4136    string fileName_;
 4137    string temporaryName_;
 4138    #endregion
 4139  }
 4140
 4141  /// <summary>
 4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.
 4143  /// </summary>
 4144  public class MemoryArchiveStorage : BaseArchiveStorage
 4145  {
 4146    #region Constructors
 4147    /// <summary>
 4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4149    /// </summary>
 4150    public MemoryArchiveStorage()
 4151      : base(FileUpdateMode.Direct)
 4152    {
 4153    }
 4154
 4155    /// <summary>
 4156    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4157    /// </summary>
 4158    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>
 4159    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>
 4160    public MemoryArchiveStorage(FileUpdateMode updateMode)
 4161      : base(updateMode)
 4162    {
 4163    }
 4164
 4165    #endregion
 4166
 4167    #region Properties
 4168    /// <summary>
 4169    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.
 4170    /// </summary>
 4171    public MemoryStream FinalStream {
 4172      get { return finalStream_; }
 4173    }
 4174
 4175    #endregion
 4176
 4177    #region IArchiveStorage Members
 4178
 4179    /// <summary>
 4180    /// Gets the temporary output <see cref="Stream"/>
 4181    /// </summary>
 4182    /// <returns>Returns the temporary output stream.</returns>
 4183    public override Stream GetTemporaryOutput()
 4184    {
 4185      temporaryStream_ = new MemoryStream();
 4186      return temporaryStream_;
 4187    }
 4188
 4189    /// <summary>
 4190    /// Converts the temporary <see cref="Stream"/> to its final form.
 4191    /// </summary>
 4192    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4193    /// the final storage for the archive.</returns>
 4194    public override Stream ConvertTemporaryToFinal()
 4195    {
 4196      if (temporaryStream_ == null) {
 4197        throw new ZipException("No temporary stream has been created");
 4198      }
 4199
 4200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());
 4201      return finalStream_;
 4202    }
 4203
 4204    /// <summary>
 4205    /// Make a temporary copy of the original stream.
 4206    /// </summary>
 4207    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4208    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4209    public override Stream MakeTemporaryCopy(Stream stream)
 4210    {
 4211      temporaryStream_ = new MemoryStream();
 4212      stream.Position = 0;
 4213      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);
 4214      return temporaryStream_;
 4215    }
 4216
 4217    /// <summary>
 4218    /// Return a stream suitable for performing direct updates on the original source.
 4219    /// </summary>
 4220    /// <param name="stream">The original source stream</param>
 4221    /// <returns>Returns a stream suitable for direct updating.</returns>
 4222    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;
 4223    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>
 4224    public override Stream OpenForDirectUpdate(Stream stream)
 4225    {
 4226      Stream result;
 4227      if ((stream == null) || !stream.CanWrite) {
 4228
 4229        result = new MemoryStream();
 4230
 4231        if (stream != null) {
 4232          stream.Position = 0;
 4233          StreamUtils.Copy(stream, result, new byte[4096]);
 4234
 4235          stream.Close();
 4236        }
 4237      } else {
 4238        result = stream;
 4239      }
 4240
 4241      return result;
 4242    }
 4243
 4244    /// <summary>
 4245    /// Disposes this instance.
 4246    /// </summary>
 4247    public override void Dispose()
 4248    {
 4249      if (temporaryStream_ != null) {
 4250        temporaryStream_.Close();
 4251      }
 4252    }
 4253
 4254    #endregion
 4255
 4256    #region Instance Fields
 4257    MemoryStream temporaryStream_;
 4258    MemoryStream finalStream_;
 4259    #endregion
 4260  }
 4261
 4262  #endregion
 4263}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_LzwConstants.htm b/docs/opencover/ICSharpCode.SharpZipLib_LzwConstants.htm new file mode 100644 index 000000000..264d8f86b --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_LzwConstants.htm @@ -0,0 +1,102 @@ + + + + +ICSharpCode.SharpZipLib.Lzw.LzwConstants - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Lzw.LzwConstants
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Lzw\LzwConstants.cs
Covered lines:0
Uncovered lines:2
Coverable lines:2
Total lines:61
Line coverage:0%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Lzw\LzwConstants.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1namespace ICSharpCode.SharpZipLib.Lzw
 2{
 3  /// <summary>
 4  /// This class contains constants used for LZW
 5  /// </summary>
 6  sealed public class LzwConstants
 7  {
 8    /// <summary>
 9    /// Magic number found at start of LZW header: 0x1f 0x9d
 10    /// </summary>
 11    public const int MAGIC = 0x1f9d;
 12
 13    /// <summary>
 14    /// Maximum number of bits per code
 15    /// </summary>
 16    public const int MAX_BITS = 16;
 17
 18    /* 3rd header byte:
 19         * bit 0..4 Number of compression bits
 20         * bit 5    Extended header
 21         * bit 6    Free
 22         * bit 7    Block mode
 23         */
 24
 25    /// <summary>
 26    /// Mask for 'number of compression bits'
 27    /// </summary>
 28    public const int BIT_MASK = 0x1f;
 29
 30    /// <summary>
 31    /// Indicates the presence of a fourth header byte
 32    /// </summary>
 33    public const int EXTENDED_MASK = 0x20;
 34    //public const int FREE_MASK      = 0x40;
 35
 36    /// <summary>
 37    /// Reserved bits
 38    /// </summary>
 39    public const int RESERVED_MASK = 0x60;
 40
 41    /// <summary>
 42    /// Block compression: if table is full and compression rate is dropping,
 43    /// clear the dictionary.
 44    /// </summary>
 45    public const int BLOCK_MODE_MASK = 0x80;
 46
 47    /// <summary>
 48    /// LZW file header size (in bytes)
 49    /// </summary>
 50    public const int HDR_SIZE = 3;
 51
 52    /// <summary>
 53    /// Initial number of bits per code
 54    /// </summary>
 55    public const int INIT_BITS = 9;
 56
 057    LzwConstants()
 58    {
 059    }
 60  }
 61}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_LzwException.htm b/docs/opencover/ICSharpCode.SharpZipLib_LzwException.htm new file mode 100644 index 000000000..c8bd1e8a0 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_LzwException.htm @@ -0,0 +1,92 @@ + + + + +ICSharpCode.SharpZipLib.Lzw.LzwException - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Lzw.LzwException
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Lzw\LzwException.cs
Covered lines:0
Uncovered lines:8
Coverable lines:8
Total lines:48
Line coverage:0%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor()100
.ctor(...)100
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Lzw\LzwException.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Runtime.Serialization;
 3
 4namespace ICSharpCode.SharpZipLib.Lzw
 5{
 6  /// <summary>
 7  /// LzwException represents exceptions specific to LZW classes and code.
 8  /// </summary>
 9  [Serializable]
 10  public class LzwException : SharpZipBaseException
 11  {
 12    /// <summary>
 13    /// Deserialization constructor
 14    /// </summary>
 15    /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
 16    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
 17    protected LzwException(SerializationInfo info, StreamingContext context)
 018      : base(info, context)
 19    {
 020    }
 21
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="LzwException" />.
 24    /// </summary>
 025    public LzwException()
 26    {
 027    }
 28
 29    /// <summary>
 30    /// Initialise a new instance of <see cref="LzwException" /> with its message string.
 31    /// </summary>
 32    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 33    public LzwException(string message)
 034      : base(message)
 35    {
 036    }
 37
 38    /// <summary>
 39    /// Initialise a new instance of <see cref="LzwException" />.
 40    /// </summary>
 41    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 42    /// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
 43    public LzwException(string message, Exception innerException)
 044      : base(message, innerException)
 45    {
 046    }
 47  }
 48}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_LzwInputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_LzwInputStream.htm new file mode 100644 index 000000000..3645793e8 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_LzwInputStream.htm @@ -0,0 +1,613 @@ + + + + +ICSharpCode.SharpZipLib.Lzw.LzwInputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Lzw.LzwInputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Lzw\LzwInputStream.cs
Covered lines:0
Uncovered lines:194
Coverable lines:194
Total lines:559
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
ReadByte()200
Read(...)2500
ResetBuf(...)100
Fill()200
ParseHeader()900
Flush()100
Seek(...)100
SetLength(...)100
Write(...)100
WriteByte(...)100
BeginWrite(...)100
Close()300
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Lzw\LzwInputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Lzw
 5{
 6  /// <summary>
 7  /// This filter stream is used to decompress a LZW format stream.
 8  /// Specifically, a stream that uses the LZC compression method.
 9  /// This file format is usually associated with the .Z file extension.
 10  ///
 11  /// See http://en.wikipedia.org/wiki/Compress
 12  /// See http://wiki.wxwidgets.org/Development:_Z_File_Format
 13  ///
 14  /// The file header consists of 3 (or optionally 4) bytes. The first two bytes
 15  /// contain the magic marker "0x1f 0x9d", followed by a byte of flags.
 16  ///
 17  /// Based on Java code by Ronald Tschalar, which in turn was based on the unlzw.c
 18  /// code in the gzip package.
 19  /// </summary>
 20  /// <example> This sample shows how to unzip a compressed file
 21  /// <code>
 22  /// using System;
 23  /// using System.IO;
 24  ///
 25  /// using ICSharpCode.SharpZipLib.Core;
 26  /// using ICSharpCode.SharpZipLib.LZW;
 27  ///
 28  /// class MainClass
 29  /// {
 30  ///   public static void Main(string[] args)
 31  ///   {
 32  ///      using (Stream inStream = new LzwInputStream(File.OpenRead(args[0])))
 33  ///      using (FileStream outStream = File.Create(Path.GetFileNameWithoutExtension(args[0]))) {
 34  ///        byte[] buffer = new byte[4096];
 35  ///        StreamUtils.Copy(inStream, outStream, buffer);
 36  ///                         // OR
 37  ///                         inStream.Read(buffer, 0, buffer.Length);
 38  ///                         // now do something with the buffer
 39  ///     }
 40  ///   }
 41  /// }
 42  /// </code>
 43  /// </example>
 44  public class LzwInputStream : Stream
 45  {
 46    /// <summary>
 47    /// Get/set flag indicating ownership of underlying stream.
 48    /// When the flag is true <see cref="Close"/> will close the underlying stream also.
 49    /// </summary>
 50    /// <remarks>
 51    /// The default value is true.
 52    /// </remarks>
 53    public bool IsStreamOwner {
 054      get { return isStreamOwner; }
 055      set { isStreamOwner = value; }
 56    }
 57
 58    /// <summary>
 59    /// Creates a LzwInputStream
 60    /// </summary>
 61    /// <param name="baseInputStream">
 62    /// The stream to read compressed data from (baseInputStream LZW format)
 63    /// </param>
 064    public LzwInputStream(Stream baseInputStream)
 65    {
 066      this.baseInputStream = baseInputStream;
 067    }
 68
 69    /// <summary>
 70    /// See <see cref="System.IO.Stream.ReadByte"/>
 71    /// </summary>
 72    /// <returns></returns>
 73    public override int ReadByte()
 74    {
 075      int b = Read(one, 0, 1);
 076       if (b == 1)
 077        return (one[0] & 0xff);
 078      return -1;
 79    }
 80
 81    /// <summary>
 82    /// Reads decompressed data into the provided buffer byte array
 83    /// </summary>
 84    /// <param name ="buffer">
 85    /// The array to read and decompress data into
 86    /// </param>
 87    /// <param name ="offset">
 88    /// The offset indicating where the data should be placed
 89    /// </param>
 90    /// <param name ="count">
 91    /// The number of bytes to decompress
 92    /// </param>
 93    /// <returns>The number of bytes read. Zero signals the end of stream</returns>
 94    public override int Read(byte[] buffer, int offset, int count)
 95    {
 096       if (!headerParsed)
 097        ParseHeader();
 98
 099       if (eof)
 0100        return 0;
 101
 0102      int start = offset;
 103
 104      /* Using local copies of various variables speeds things up by as
 105           * much as 30% in Java! Performance not tested in C#.
 106           */
 0107      int[] lTabPrefix = tabPrefix;
 0108      byte[] lTabSuffix = tabSuffix;
 0109      byte[] lStack = stack;
 0110      int lNBits = nBits;
 0111      int lMaxCode = maxCode;
 0112      int lMaxMaxCode = maxMaxCode;
 0113      int lBitMask = bitMask;
 0114      int lOldCode = oldCode;
 0115      byte lFinChar = finChar;
 0116      int lStackP = stackP;
 0117      int lFreeEnt = freeEnt;
 0118      byte[] lData = data;
 0119      int lBitPos = bitPos;
 120
 121
 122      // empty stack if stuff still left
 0123      int sSize = lStack.Length - lStackP;
 0124       if (sSize > 0) {
 0125         int num = (sSize >= count) ? count : sSize;
 0126        Array.Copy(lStack, lStackP, buffer, offset, num);
 0127        offset += num;
 0128        count -= num;
 0129        lStackP += num;
 130      }
 131
 0132       if (count == 0) {
 0133        stackP = lStackP;
 0134        return offset - start;
 135      }
 136
 137
 138      // loop, filling local buffer until enough data has been decompressed
 139      MainLoop:
 140      do {
 0141         if (end < EXTRA) {
 0142          Fill();
 143        }
 144
 0145        int bitIn = (got > 0) ? (end - end % lNBits) << 3 :
 0146                    (end << 3) - (lNBits - 1);
 147
 0148         while (lBitPos < bitIn) {
 149          #region A
 150          // handle 1-byte reads correctly
 0151           if (count == 0) {
 0152            nBits = lNBits;
 0153            maxCode = lMaxCode;
 0154            maxMaxCode = lMaxMaxCode;
 0155            bitMask = lBitMask;
 0156            oldCode = lOldCode;
 0157            finChar = lFinChar;
 0158            stackP = lStackP;
 0159            freeEnt = lFreeEnt;
 0160            bitPos = lBitPos;
 161
 0162            return offset - start;
 163          }
 164
 165          // check for code-width expansion
 0166           if (lFreeEnt > lMaxCode) {
 0167            int nBytes = lNBits << 3;
 0168            lBitPos = (lBitPos - 1) +
 0169            nBytes - (lBitPos - 1 + nBytes) % nBytes;
 170
 0171            lNBits++;
 0172            lMaxCode = (lNBits == maxBits) ? lMaxMaxCode :
 0173                            (1 << lNBits) - 1;
 174
 0175            lBitMask = (1 << lNBits) - 1;
 0176            lBitPos = ResetBuf(lBitPos);
 0177            goto MainLoop;
 178          }
 179          #endregion
 180
 181          #region B
 182          // read next code
 0183          int pos = lBitPos >> 3;
 0184          int code = (((lData[pos] & 0xFF) |
 0185            ((lData[pos + 1] & 0xFF) << 8) |
 0186            ((lData[pos + 2] & 0xFF) << 16)) >>
 0187            (lBitPos & 0x7)) & lBitMask;
 188
 0189          lBitPos += lNBits;
 190
 191          // handle first iteration
 0192           if (lOldCode == -1) {
 0193             if (code >= 256)
 0194              throw new LzwException("corrupt input: " + code + " > 255");
 195
 0196            lFinChar = (byte)(lOldCode = code);
 0197            buffer[offset++] = lFinChar;
 0198            count--;
 0199            continue;
 200          }
 201
 202          // handle CLEAR code
 0203           if (code == TBL_CLEAR && blockMode) {
 0204            Array.Copy(zeros, 0, lTabPrefix, 0, zeros.Length);
 0205            lFreeEnt = TBL_FIRST - 1;
 206
 0207            int nBytes = lNBits << 3;
 0208            lBitPos = (lBitPos - 1) + nBytes - (lBitPos - 1 + nBytes) % nBytes;
 0209            lNBits = LzwConstants.INIT_BITS;
 0210            lMaxCode = (1 << lNBits) - 1;
 0211            lBitMask = lMaxCode;
 212
 213            // Code tables reset
 214
 0215            lBitPos = ResetBuf(lBitPos);
 0216            goto MainLoop;
 217          }
 218          #endregion
 219
 220          #region C
 221          // setup
 0222          int inCode = code;
 0223          lStackP = lStack.Length;
 224
 225          // Handle KwK case
 0226           if (code >= lFreeEnt) {
 0227             if (code > lFreeEnt) {
 0228              throw new LzwException("corrupt input: code=" + code +
 0229                ", freeEnt=" + lFreeEnt);
 230            }
 231
 0232            lStack[--lStackP] = lFinChar;
 0233            code = lOldCode;
 234          }
 235
 236          // Generate output characters in reverse order
 0237           while (code >= 256) {
 0238            lStack[--lStackP] = lTabSuffix[code];
 0239            code = lTabPrefix[code];
 240          }
 241
 0242          lFinChar = lTabSuffix[code];
 0243          buffer[offset++] = lFinChar;
 0244          count--;
 245
 246          // And put them out in forward order
 0247          sSize = lStack.Length - lStackP;
 0248           int num = (sSize >= count) ? count : sSize;
 0249          Array.Copy(lStack, lStackP, buffer, offset, num);
 0250          offset += num;
 0251          count -= num;
 0252          lStackP += num;
 253          #endregion
 254
 255          #region D
 256          // generate new entry in table
 0257           if (lFreeEnt < lMaxMaxCode) {
 0258            lTabPrefix[lFreeEnt] = lOldCode;
 0259            lTabSuffix[lFreeEnt] = lFinChar;
 0260            lFreeEnt++;
 261          }
 262
 263          // Remember previous code
 0264          lOldCode = inCode;
 265
 266          // if output buffer full, then return
 0267           if (count == 0) {
 0268            nBits = lNBits;
 0269            maxCode = lMaxCode;
 0270            bitMask = lBitMask;
 0271            oldCode = lOldCode;
 0272            finChar = lFinChar;
 0273            stackP = lStackP;
 0274            freeEnt = lFreeEnt;
 0275            bitPos = lBitPos;
 276
 0277            return offset - start;
 278          }
 279          #endregion
 280        }   // while
 281
 0282        lBitPos = ResetBuf(lBitPos);
 283
 0284       } while (got > 0);  // do..while
 285
 0286      nBits = lNBits;
 0287      maxCode = lMaxCode;
 0288      bitMask = lBitMask;
 0289      oldCode = lOldCode;
 0290      finChar = lFinChar;
 0291      stackP = lStackP;
 0292      freeEnt = lFreeEnt;
 0293      bitPos = lBitPos;
 294
 0295      eof = true;
 0296      return offset - start;
 297    }
 298
 299    /// <summary>
 300    /// Moves the unread data in the buffer to the beginning and resets
 301    /// the pointers.
 302    /// </summary>
 303    /// <param name="bitPosition"></param>
 304    /// <returns></returns>
 305    private int ResetBuf(int bitPosition)
 306    {
 0307      int pos = bitPosition >> 3;
 0308      Array.Copy(data, pos, data, 0, end - pos);
 0309      end -= pos;
 0310      return 0;
 311    }
 312
 313
 314    private void Fill()
 315    {
 0316      got = baseInputStream.Read(data, end, data.Length - 1 - end);
 0317       if (got > 0) {
 0318        end += got;
 319      }
 0320    }
 321
 322
 323    private void ParseHeader()
 324    {
 0325      headerParsed = true;
 326
 0327      byte[] hdr = new byte[LzwConstants.HDR_SIZE];
 328
 0329      int result = baseInputStream.Read(hdr, 0, hdr.Length);
 330
 331      // Check the magic marker
 0332       if (result < 0)
 0333        throw new LzwException("Failed to read LZW header");
 334
 0335       if (hdr[0] != (LzwConstants.MAGIC >> 8) || hdr[1] != (LzwConstants.MAGIC & 0xff)) {
 0336        throw new LzwException(String.Format(
 0337          "Wrong LZW header. Magic bytes don't match. 0x{0:x2} 0x{1:x2}",
 0338          hdr[0], hdr[1]));
 339      }
 340
 341      // Check the 3rd header byte
 0342      blockMode = (hdr[2] & LzwConstants.BLOCK_MODE_MASK) > 0;
 0343      maxBits = hdr[2] & LzwConstants.BIT_MASK;
 344
 0345       if (maxBits > LzwConstants.MAX_BITS) {
 0346        throw new LzwException("Stream compressed with " + maxBits +
 0347          " bits, but decompression can only handle " +
 0348          LzwConstants.MAX_BITS + " bits.");
 349      }
 350
 0351       if ((hdr[2] & LzwConstants.RESERVED_MASK) > 0) {
 0352        throw new LzwException("Unsupported bits set in the header.");
 353      }
 354
 355      // Initialize variables
 0356      maxMaxCode = 1 << maxBits;
 0357      nBits = LzwConstants.INIT_BITS;
 0358      maxCode = (1 << nBits) - 1;
 0359      bitMask = maxCode;
 0360      oldCode = -1;
 0361      finChar = 0;
 0362       freeEnt = blockMode ? TBL_FIRST : 256;
 363
 0364      tabPrefix = new int[1 << maxBits];
 0365      tabSuffix = new byte[1 << maxBits];
 0366      stack = new byte[1 << maxBits];
 0367      stackP = stack.Length;
 368
 0369       for (int idx = 255; idx >= 0; idx--)
 0370        tabSuffix[idx] = (byte)idx;
 0371    }
 372
 373    #region Stream Overrides
 374    /// <summary>
 375    /// Gets a value indicating whether the current stream supports reading
 376    /// </summary>
 377    public override bool CanRead {
 378      get {
 0379        return baseInputStream.CanRead;
 380      }
 381    }
 382
 383    /// <summary>
 384    /// Gets a value of false indicating seeking is not supported for this stream.
 385    /// </summary>
 386    public override bool CanSeek {
 387      get {
 0388        return false;
 389      }
 390    }
 391
 392    /// <summary>
 393    /// Gets a value of false indicating that this stream is not writeable.
 394    /// </summary>
 395    public override bool CanWrite {
 396      get {
 0397        return false;
 398      }
 399    }
 400
 401    /// <summary>
 402    /// A value representing the length of the stream in bytes.
 403    /// </summary>
 404    public override long Length {
 405      get {
 0406        return got;
 407      }
 408    }
 409
 410    /// <summary>
 411    /// The current position within the stream.
 412    /// Throws a NotSupportedException when attempting to set the position
 413    /// </summary>
 414    /// <exception cref="NotSupportedException">Attempting to set the position</exception>
 415    public override long Position {
 416      get {
 0417        return baseInputStream.Position;
 418      }
 419      set {
 0420        throw new NotSupportedException("InflaterInputStream Position not supported");
 421      }
 422    }
 423
 424    /// <summary>
 425    /// Flushes the baseInputStream
 426    /// </summary>
 427    public override void Flush()
 428    {
 0429      baseInputStream.Flush();
 0430    }
 431
 432    /// <summary>
 433    /// Sets the position within the current stream
 434    /// Always throws a NotSupportedException
 435    /// </summary>
 436    /// <param name="offset">The relative offset to seek to.</param>
 437    /// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>
 438    /// <returns>The new position in the stream.</returns>
 439    /// <exception cref="NotSupportedException">Any access</exception>
 440    public override long Seek(long offset, SeekOrigin origin)
 441    {
 0442      throw new NotSupportedException("Seek not supported");
 443    }
 444
 445    /// <summary>
 446    /// Set the length of the current stream
 447    /// Always throws a NotSupportedException
 448    /// </summary>
 449    /// <param name="value">The new length value for the stream.</param>
 450    /// <exception cref="NotSupportedException">Any access</exception>
 451    public override void SetLength(long value)
 452    {
 0453      throw new NotSupportedException("InflaterInputStream SetLength not supported");
 454    }
 455
 456    /// <summary>
 457    /// Writes a sequence of bytes to stream and advances the current position
 458    /// This method always throws a NotSupportedException
 459    /// </summary>
 460    /// <param name="buffer">Thew buffer containing data to write.</param>
 461    /// <param name="offset">The offset of the first byte to write.</param>
 462    /// <param name="count">The number of bytes to write.</param>
 463    /// <exception cref="NotSupportedException">Any access</exception>
 464    public override void Write(byte[] buffer, int offset, int count)
 465    {
 0466      throw new NotSupportedException("InflaterInputStream Write not supported");
 467    }
 468
 469    /// <summary>
 470    /// Writes one byte to the current stream and advances the current position
 471    /// Always throws a NotSupportedException
 472    /// </summary>
 473    /// <param name="value">The byte to write.</param>
 474    /// <exception cref="NotSupportedException">Any access</exception>
 475    public override void WriteByte(byte value)
 476    {
 0477      throw new NotSupportedException("InflaterInputStream WriteByte not supported");
 478    }
 479
 480    /// <summary>
 481    /// Entry point to begin an asynchronous write.  Always throws a NotSupportedException.
 482    /// </summary>
 483    /// <param name="buffer">The buffer to write data from</param>
 484    /// <param name="offset">Offset of first byte to write</param>
 485    /// <param name="count">The maximum number of bytes to write</param>
 486    /// <param name="callback">The method to be called when the asynchronous write operation is completed</param>
 487    /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from ot
 488    /// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>
 489    /// <exception cref="NotSupportedException">Any access</exception>
 490    public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
 491    {
 0492      throw new NotSupportedException("InflaterInputStream BeginWrite not supported");
 493    }
 494
 495    /// <summary>
 496    /// Closes the input stream.  When <see cref="IsStreamOwner"></see>
 497    /// is true the underlying stream is also closed.
 498    /// </summary>
 499    public override void Close()
 500    {
 0501       if (!isClosed) {
 0502        isClosed = true;
 0503         if (isStreamOwner) {
 0504          baseInputStream.Close();
 505        }
 506      }
 0507    }
 508
 509    #endregion
 510
 511    #region Instance Fields
 512
 513    Stream baseInputStream;
 514
 515    /// <summary>
 516    /// Flag indicating wether this instance is designated the stream owner.
 517    /// When closing if this flag is true the underlying stream is closed.
 518    /// </summary>
 0519    bool isStreamOwner = true;
 520
 521    /// <summary>
 522    /// Flag indicating wether this instance has been closed or not.
 523    /// </summary>
 524    bool isClosed;
 525
 0526    readonly byte[] one = new byte[1];
 527    bool headerParsed;
 528
 529    // string table stuff
 530    private const int TBL_CLEAR = 0x100;
 531    private const int TBL_FIRST = TBL_CLEAR + 1;
 532
 533    private int[] tabPrefix;
 534    private byte[] tabSuffix;
 0535    private readonly int[] zeros = new int[256];
 536    private byte[] stack;
 537
 538    // various state
 539    private bool blockMode;
 540    private int nBits;
 541    private int maxBits;
 542    private int maxMaxCode;
 543    private int maxCode;
 544    private int bitMask;
 545    private int oldCode;
 546    private byte finChar;
 547    private int stackP;
 548    private int freeEnt;
 549
 550    // input buffer
 0551    private readonly byte[] data = new byte[1024 * 8];
 552    private int bitPos;
 553    private int end;
 554    int got;
 555    private bool eof;
 556    private const int EXTRA = 64;
 557    #endregion
 558  }
 559}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_MemoryArchiveStorage.htm b/docs/opencover/ICSharpCode.SharpZipLib_MemoryArchiveStorage.htm new file mode 100644 index 000000000..575c23086 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_MemoryArchiveStorage.htm @@ -0,0 +1,4311 @@ + + + + +ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs
Covered lines:15
Uncovered lines:12
Coverable lines:27
Total lines:4263
Line coverage:55.5%
Branch coverage:50%
+

Metrics

+ + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
.ctor(...)1100100
GetTemporaryOutput()1100100
ConvertTemporaryToFinal()27566.67
MakeTemporaryCopy(...)100
OpenForDirectUpdate(...)433.3342.86
Dispose()2100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.IO;
 4using System.Text;
 5using System.Globalization;
 6using System.Security.Cryptography;
 7using ICSharpCode.SharpZipLib.Encryption;
 8using ICSharpCode.SharpZipLib.Core;
 9using ICSharpCode.SharpZipLib.Checksum;
 10using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 11using ICSharpCode.SharpZipLib.Zip.Compression;
 12
 13namespace ICSharpCode.SharpZipLib.Zip
 14{
 15  #region Keys Required Event Args
 16  /// <summary>
 17  /// Arguments used with KeysRequiredEvent
 18  /// </summary>
 19  public class KeysRequiredEventArgs : EventArgs
 20  {
 21    #region Constructors
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 24    /// </summary>
 25    /// <param name="name">The name of the file for which keys are required.</param>
 26    public KeysRequiredEventArgs(string name)
 27    {
 28      fileName = name;
 29    }
 30
 31    /// <summary>
 32    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 33    /// </summary>
 34    /// <param name="name">The name of the file for which keys are required.</param>
 35    /// <param name="keyValue">The current key value.</param>
 36    public KeysRequiredEventArgs(string name, byte[] keyValue)
 37    {
 38      fileName = name;
 39      key = keyValue;
 40    }
 41
 42    #endregion
 43    #region Properties
 44    /// <summary>
 45    /// Gets the name of the file for which keys are required.
 46    /// </summary>
 47    public string FileName {
 48      get { return fileName; }
 49    }
 50
 51    /// <summary>
 52    /// Gets or sets the key value
 53    /// </summary>
 54    public byte[] Key {
 55      get { return key; }
 56      set { key = value; }
 57    }
 58    #endregion
 59
 60    #region Instance Fields
 61    string fileName;
 62    byte[] key;
 63    #endregion
 64  }
 65  #endregion
 66
 67  #region Test Definitions
 68  /// <summary>
 69  /// The strategy to apply to testing.
 70  /// </summary>
 71  public enum TestStrategy
 72  {
 73    /// <summary>
 74    /// Find the first error only.
 75    /// </summary>
 76    FindFirstError,
 77    /// <summary>
 78    /// Find all possible errors.
 79    /// </summary>
 80    FindAllErrors,
 81  }
 82
 83  /// <summary>
 84  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.
 85  /// </summary>
 86  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 87  public enum TestOperation
 88  {
 89    /// <summary>
 90    /// Setting up testing.
 91    /// </summary>
 92    Initialising,
 93
 94    /// <summary>
 95    /// Testing an individual entries header
 96    /// </summary>
 97    EntryHeader,
 98
 99    /// <summary>
 100    /// Testing an individual entries data
 101    /// </summary>
 102    EntryData,
 103
 104    /// <summary>
 105    /// Testing an individual entry has completed.
 106    /// </summary>
 107    EntryComplete,
 108
 109    /// <summary>
 110    /// Running miscellaneous tests
 111    /// </summary>
 112    MiscellaneousTests,
 113
 114    /// <summary>
 115    /// Testing is complete
 116    /// </summary>
 117    Complete,
 118  }
 119
 120  /// <summary>
 121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.
 122  /// </summary>
 123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 124  public class TestStatus
 125  {
 126    #region Constructors
 127    /// <summary>
 128    /// Initialise a new instance of <see cref="TestStatus"/>
 129    /// </summary>
 130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>
 131    public TestStatus(ZipFile file)
 132    {
 133      file_ = file;
 134    }
 135    #endregion
 136
 137    #region Properties
 138
 139    /// <summary>
 140    /// Get the current <see cref="TestOperation"/> in progress.
 141    /// </summary>
 142    public TestOperation Operation {
 143      get { return operation_; }
 144    }
 145
 146    /// <summary>
 147    /// Get the <see cref="ZipFile"/> this status is applicable to.
 148    /// </summary>
 149    public ZipFile File {
 150      get { return file_; }
 151    }
 152
 153    /// <summary>
 154    /// Get the current/last entry tested.
 155    /// </summary>
 156    public ZipEntry Entry {
 157      get { return entry_; }
 158    }
 159
 160    /// <summary>
 161    /// Get the number of errors detected so far.
 162    /// </summary>
 163    public int ErrorCount {
 164      get { return errorCount_; }
 165    }
 166
 167    /// <summary>
 168    /// Get the number of bytes tested so far for the current entry.
 169    /// </summary>
 170    public long BytesTested {
 171      get { return bytesTested_; }
 172    }
 173
 174    /// <summary>
 175    /// Get a value indicating wether the last entry test was valid.
 176    /// </summary>
 177    public bool EntryValid {
 178      get { return entryValid_; }
 179    }
 180    #endregion
 181
 182    #region Internal API
 183    internal void AddError()
 184    {
 185      errorCount_++;
 186      entryValid_ = false;
 187    }
 188
 189    internal void SetOperation(TestOperation operation)
 190    {
 191      operation_ = operation;
 192    }
 193
 194    internal void SetEntry(ZipEntry entry)
 195    {
 196      entry_ = entry;
 197      entryValid_ = true;
 198      bytesTested_ = 0;
 199    }
 200
 201    internal void SetBytesTested(long value)
 202    {
 203      bytesTested_ = value;
 204    }
 205    #endregion
 206
 207    #region Instance Fields
 208    ZipFile file_;
 209    ZipEntry entry_;
 210    bool entryValid_;
 211    int errorCount_;
 212    long bytesTested_;
 213    TestOperation operation_;
 214    #endregion
 215  }
 216
 217  /// <summary>
 218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if
 219  /// </summary>
 220  /// <remarks>If the message is non-null an error has occured.  If the message is null
 221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>
 222  public delegate void ZipTestResultHandler(TestStatus status, string message);
 223  #endregion
 224
 225  #region Update Definitions
 226  /// <summary>
 227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.
 228  /// </summary>
 229  public enum FileUpdateMode
 230  {
 231    /// <summary>
 232    /// Perform all updates on temporary files ensuring that the original file is saved.
 233    /// </summary>
 234    Safe,
 235    /// <summary>
 236    /// Update the archive directly, which is faster but less safe.
 237    /// </summary>
 238    Direct,
 239  }
 240  #endregion
 241
 242  #region ZipFile Class
 243  /// <summary>
 244  /// This class represents a Zip archive.  You can ask for the contained
 245  /// entries, or get an input stream for a file entry.  The entry is
 246  /// automatically decompressed.
 247  ///
 248  /// You can also update the archive adding or deleting entries.
 249  ///
 250  /// This class is thread safe for input:  You can open input streams for arbitrary
 251  /// entries in different threads.
 252  /// <br/>
 253  /// <br/>Author of the original java version : Jochen Hoenicke
 254  /// </summary>
 255  /// <example>
 256  /// <code>
 257  /// using System;
 258  /// using System.Text;
 259  /// using System.Collections;
 260  /// using System.IO;
 261  ///
 262  /// using ICSharpCode.SharpZipLib.Zip;
 263  ///
 264  /// class MainClass
 265  /// {
 266  ///   static public void Main(string[] args)
 267  ///   {
 268  ///     using (ZipFile zFile = new ZipFile(args[0])) {
 269  ///       Console.WriteLine("Listing of : " + zFile.Name);
 270  ///       Console.WriteLine("");
 271  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");
 272  ///       Console.WriteLine("--------  --------  --------  ------  ---------");
 273  ///       foreach (ZipEntry e in zFile) {
 274  ///         if ( e.IsFile ) {
 275  ///           DateTime d = e.DateTime;
 276  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,
 277  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),
 278  ///             e.Name);
 279  ///         }
 280  ///       }
 281  ///     }
 282  ///   }
 283  /// }
 284  /// </code>
 285  /// </example>
 286  public class ZipFile : IEnumerable, IDisposable
 287  {
 288    #region KeyHandling
 289
 290    /// <summary>
 291    /// Delegate for handling keys/password setting during compresion/decompression.
 292    /// </summary>
 293    public delegate void KeysRequiredEventHandler(
 294      object sender,
 295      KeysRequiredEventArgs e
 296    );
 297
 298    /// <summary>
 299    /// Event handler for handling encryption keys.
 300    /// </summary>
 301    public KeysRequiredEventHandler KeysRequired;
 302
 303    /// <summary>
 304    /// Handles getting of encryption keys when required.
 305    /// </summary>
 306    /// <param name="fileName">The file for which encryption keys are required.</param>
 307    void OnKeysRequired(string fileName)
 308    {
 309      if (KeysRequired != null) {
 310        var krea = new KeysRequiredEventArgs(fileName, key);
 311        KeysRequired(this, krea);
 312        key = krea.Key;
 313      }
 314    }
 315
 316    /// <summary>
 317    /// Get/set the encryption key value.
 318    /// </summary>
 319    byte[] Key {
 320      get { return key; }
 321      set { key = value; }
 322    }
 323
 324    /// <summary>
 325    /// Password to be used for encrypting/decrypting files.
 326    /// </summary>
 327    /// <remarks>Set to null if no password is required.</remarks>
 328    public string Password {
 329      set {
 330        if (string.IsNullOrEmpty(value)) {
 331          key = null;
 332        } else {
 333          rawPassword_ = value;
 334          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));
 335        }
 336      }
 337    }
 338
 339    /// <summary>
 340    /// Get a value indicating wether encryption keys are currently available.
 341    /// </summary>
 342    bool HaveKeys {
 343      get { return key != null; }
 344    }
 345    #endregion
 346
 347    #region Constructors
 348    /// <summary>
 349    /// Opens a Zip file with the given name for reading.
 350    /// </summary>
 351    /// <param name="name">The name of the file to open.</param>
 352    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>
 353    /// <exception cref="IOException">
 354    /// An i/o error occurs
 355    /// </exception>
 356    /// <exception cref="ZipException">
 357    /// The file doesn't contain a valid zip archive.
 358    /// </exception>
 359    public ZipFile(string name)
 360    {
 361      if (name == null) {
 362        throw new ArgumentNullException(nameof(name));
 363      }
 364
 365      name_ = name;
 366
 367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 368      isStreamOwner = true;
 369
 370      try {
 371        ReadEntries();
 372      } catch {
 373        DisposeInternal(true);
 374        throw;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Opens a Zip file reading the given <see cref="FileStream"/>.
 380    /// </summary>
 381    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>
 382    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>
 383    /// <exception cref="IOException">
 384    /// An i/o error occurs.
 385    /// </exception>
 386    /// <exception cref="ZipException">
 387    /// The file doesn't contain a valid zip archive.
 388    /// </exception>
 389    public ZipFile(FileStream file)
 390    {
 391      if (file == null) {
 392        throw new ArgumentNullException(nameof(file));
 393      }
 394
 395      if (!file.CanSeek) {
 396        throw new ArgumentException("Stream is not seekable", nameof(file));
 397      }
 398
 399      baseStream_ = file;
 400      name_ = file.Name;
 401      isStreamOwner = true;
 402
 403      try {
 404        ReadEntries();
 405      } catch {
 406        DisposeInternal(true);
 407        throw;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Opens a Zip file reading the given <see cref="Stream"/>.
 413    /// </summary>
 414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
 415    /// <exception cref="IOException">
 416    /// An i/o error occurs
 417    /// </exception>
 418    /// <exception cref="ZipException">
 419    /// The stream doesn't contain a valid zip archive.<br/>
 420    /// </exception>
 421    /// <exception cref="ArgumentException">
 422    /// The <see cref="Stream">stream</see> doesnt support seeking.
 423    /// </exception>
 424    /// <exception cref="ArgumentNullException">
 425    /// The <see cref="Stream">stream</see> argument is null.
 426    /// </exception>
 427    public ZipFile(Stream stream)
 428    {
 429      if (stream == null) {
 430        throw new ArgumentNullException(nameof(stream));
 431      }
 432
 433      if (!stream.CanSeek) {
 434        throw new ArgumentException("Stream is not seekable", nameof(stream));
 435      }
 436
 437      baseStream_ = stream;
 438      isStreamOwner = true;
 439
 440      if (baseStream_.Length > 0) {
 441        try {
 442          ReadEntries();
 443        } catch {
 444          DisposeInternal(true);
 445          throw;
 446        }
 447      } else {
 448        entries_ = new ZipEntry[0];
 449        isNewArchive_ = true;
 450      }
 451    }
 452
 453    /// <summary>
 454    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
 455    /// </summary>
 456    internal ZipFile()
 457    {
 458      entries_ = new ZipEntry[0];
 459      isNewArchive_ = true;
 460    }
 461
 462    #endregion
 463
 464    #region Destructors and Closing
 465    /// <summary>
 466    /// Finalize this instance.
 467    /// </summary>
 468    ~ZipFile()
 469    {
 470      Dispose(false);
 471    }
 472
 473    /// <summary>
 474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying
 475    /// Once closed, no further instance methods should be called.
 476    /// </summary>
 477    /// <exception cref="System.IO.IOException">
 478    /// An i/o error occurs.
 479    /// </exception>
 480    public void Close()
 481    {
 482      DisposeInternal(true);
 483      GC.SuppressFinalize(this);
 484    }
 485
 486    #endregion
 487
 488    #region Creators
 489    /// <summary>
 490    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.
 491    /// </summary>
 492    /// <param name="fileName">The name of the archive to create.</param>
 493    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 494    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>
 495    public static ZipFile Create(string fileName)
 496    {
 497      if (fileName == null) {
 498        throw new ArgumentNullException(nameof(fileName));
 499      }
 500
 501      FileStream fs = File.Create(fileName);
 502
 503      var result = new ZipFile();
 504      result.name_ = fileName;
 505      result.baseStream_ = fs;
 506      result.isStreamOwner = true;
 507      return result;
 508    }
 509
 510    /// <summary>
 511    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.
 512    /// </summary>
 513    /// <param name="outStream">The stream providing data storage.</param>
 514    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 515    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>
 516    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>
 517    public static ZipFile Create(Stream outStream)
 518    {
 519      if (outStream == null) {
 520        throw new ArgumentNullException(nameof(outStream));
 521      }
 522
 523      if (!outStream.CanWrite) {
 524        throw new ArgumentException("Stream is not writeable", nameof(outStream));
 525      }
 526
 527      if (!outStream.CanSeek) {
 528        throw new ArgumentException("Stream is not seekable", nameof(outStream));
 529      }
 530
 531      var result = new ZipFile();
 532      result.baseStream_ = outStream;
 533      return result;
 534    }
 535
 536    #endregion
 537
 538    #region Properties
 539    /// <summary>
 540    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
 541    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
 542    /// </summary>
 543    /// <remarks>
 544    /// The default value is true in all cases.
 545    /// </remarks>
 546    public bool IsStreamOwner {
 547      get { return isStreamOwner; }
 548      set { isStreamOwner = value; }
 549    }
 550
 551    /// <summary>
 552    /// Get a value indicating wether
 553    /// this archive is embedded in another file or not.
 554    /// </summary>
 555    public bool IsEmbeddedArchive {
 556      // Not strictly correct in all circumstances currently
 557      get { return offsetOfFirstEntry > 0; }
 558    }
 559
 560    /// <summary>
 561    /// Get a value indicating that this archive is a new one.
 562    /// </summary>
 563    public bool IsNewArchive {
 564      get { return isNewArchive_; }
 565    }
 566
 567    /// <summary>
 568    /// Gets the comment for the zip file.
 569    /// </summary>
 570    public string ZipFileComment {
 571      get { return comment_; }
 572    }
 573
 574    /// <summary>
 575    /// Gets the name of this zip file.
 576    /// </summary>
 577    public string Name {
 578      get { return name_; }
 579    }
 580
 581    /// <summary>
 582    /// Gets the number of entries in this zip file.
 583    /// </summary>
 584    /// <exception cref="InvalidOperationException">
 585    /// The Zip file has been closed.
 586    /// </exception>
 587    [Obsolete("Use the Count property instead")]
 588    public int Size {
 589      get {
 590        return entries_.Length;
 591      }
 592    }
 593
 594    /// <summary>
 595    /// Get the number of entries contained in this <see cref="ZipFile"/>.
 596    /// </summary>
 597    public long Count {
 598      get {
 599        return entries_.Length;
 600      }
 601    }
 602
 603    /// <summary>
 604    /// Indexer property for ZipEntries
 605    /// </summary>
 606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
 607    public ZipEntry this[int index] {
 608      get {
 609        return (ZipEntry)entries_[index].Clone();
 610      }
 611    }
 612
 613    #endregion
 614
 615    #region Input Handling
 616    /// <summary>
 617    /// Gets an enumerator for the Zip entries in this Zip file.
 618    /// </summary>
 619    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>
 620    /// <exception cref="ObjectDisposedException">
 621    /// The Zip file has been closed.
 622    /// </exception>
 623    public IEnumerator GetEnumerator()
 624    {
 625      if (isDisposed_) {
 626        throw new ObjectDisposedException("ZipFile");
 627      }
 628
 629      return new ZipEntryEnumerator(entries_);
 630    }
 631
 632    /// <summary>
 633    /// Return the index of the entry with a matching name
 634    /// </summary>
 635    /// <param name="name">Entry name to find</param>
 636    /// <param name="ignoreCase">If true the comparison is case insensitive</param>
 637    /// <returns>The index position of the matching entry or -1 if not found</returns>
 638    /// <exception cref="ObjectDisposedException">
 639    /// The Zip file has been closed.
 640    /// </exception>
 641    public int FindEntry(string name, bool ignoreCase)
 642    {
 643      if (isDisposed_) {
 644        throw new ObjectDisposedException("ZipFile");
 645      }
 646
 647      // TODO: This will be slow as the next ice age for huge archives!
 648      for (int i = 0; i < entries_.Length; i++) {
 649        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {
 650          return i;
 651        }
 652      }
 653      return -1;
 654    }
 655
 656    /// <summary>
 657    /// Searches for a zip entry in this archive with the given name.
 658    /// String comparisons are case insensitive
 659    /// </summary>
 660    /// <param name="name">
 661    /// The name to find. May contain directory components separated by slashes ('/').
 662    /// </param>
 663    /// <returns>
 664    /// A clone of the zip entry, or null if no entry with that name exists.
 665    /// </returns>
 666    /// <exception cref="ObjectDisposedException">
 667    /// The Zip file has been closed.
 668    /// </exception>
 669    public ZipEntry GetEntry(string name)
 670    {
 671      if (isDisposed_) {
 672        throw new ObjectDisposedException("ZipFile");
 673      }
 674
 675      int index = FindEntry(name, true);
 676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;
 677    }
 678
 679    /// <summary>
 680    /// Gets an input stream for reading the given zip entry data in an uncompressed form.
 681    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
 682    /// </summary>
 683    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
 684    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
 685    /// <exception cref="ObjectDisposedException">
 686    /// The ZipFile has already been closed
 687    /// </exception>
 688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 689    /// The compression method for the entry is unknown
 690    /// </exception>
 691    /// <exception cref="IndexOutOfRangeException">
 692    /// The entry is not found in the ZipFile
 693    /// </exception>
 694    public Stream GetInputStream(ZipEntry entry)
 695    {
 696      if (entry == null) {
 697        throw new ArgumentNullException(nameof(entry));
 698      }
 699
 700      if (isDisposed_) {
 701        throw new ObjectDisposedException("ZipFile");
 702      }
 703
 704      long index = entry.ZipFileIndex;
 705      if ((index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name)) {
 706        index = FindEntry(entry.Name, true);
 707        if (index < 0) {
 708          throw new ZipException("Entry cannot be found");
 709        }
 710      }
 711      return GetInputStream(index);
 712    }
 713
 714    /// <summary>
 715    /// Creates an input stream reading a zip entry
 716    /// </summary>
 717    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
 718    /// <returns>
 719    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>
 720    /// </returns>
 721    /// <exception cref="ObjectDisposedException">
 722    /// The ZipFile has already been closed
 723    /// </exception>
 724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 725    /// The compression method for the entry is unknown
 726    /// </exception>
 727    /// <exception cref="IndexOutOfRangeException">
 728    /// The entry is not found in the ZipFile
 729    /// </exception>
 730    public Stream GetInputStream(long entryIndex)
 731    {
 732      if (isDisposed_) {
 733        throw new ObjectDisposedException("ZipFile");
 734      }
 735
 736      long start = LocateEntry(entries_[entryIndex]);
 737      CompressionMethod method = entries_[entryIndex].CompressionMethod;
 738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);
 739
 740      if (entries_[entryIndex].IsCrypted == true) {
 741        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);
 742        if (result == null) {
 743          throw new ZipException("Unable to decrypt this entry");
 744        }
 745      }
 746
 747      switch (method) {
 748        case CompressionMethod.Stored:
 749          // read as is.
 750          break;
 751
 752        case CompressionMethod.Deflated:
 753          // No need to worry about ownership and closing as underlying stream close does nothing.
 754          result = new InflaterInputStream(result, new Inflater(true));
 755          break;
 756
 757        default:
 758          throw new ZipException("Unsupported compression method " + method);
 759      }
 760
 761      return result;
 762    }
 763
 764    #endregion
 765
 766    #region Archive Testing
 767    /// <summary>
 768    /// Test an archive for integrity/validity
 769    /// </summary>
 770    /// <param name="testData">Perform low level data Crc check</param>
 771    /// <returns>true if all tests pass, false otherwise</returns>
 772    /// <remarks>Testing will terminate on the first error found.</remarks>
 773    public bool TestArchive(bool testData)
 774    {
 775      return TestArchive(testData, TestStrategy.FindFirstError, null);
 776    }
 777
 778    /// <summary>
 779    /// Test an archive for integrity/validity
 780    /// </summary>
 781    /// <param name="testData">Perform low level data Crc check</param>
 782    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
 783    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
 784    /// <returns>true if all tests pass, false otherwise</returns>
 785    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>
 786    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
 787    {
 788      if (isDisposed_) {
 789        throw new ObjectDisposedException("ZipFile");
 790      }
 791
 792      var status = new TestStatus(this);
 793
 794      if (resultHandler != null) {
 795        resultHandler(status, null);
 796      }
 797
 798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;
 799
 800      bool testing = true;
 801
 802      try {
 803        int entryIndex = 0;
 804
 805        while (testing && (entryIndex < Count)) {
 806          if (resultHandler != null) {
 807            status.SetEntry(this[entryIndex]);
 808            status.SetOperation(TestOperation.EntryHeader);
 809            resultHandler(status, null);
 810          }
 811
 812          try {
 813            TestLocalHeader(this[entryIndex], test);
 814          } catch (ZipException ex) {
 815            status.AddError();
 816
 817            if (resultHandler != null) {
 818              resultHandler(status,
 819                string.Format("Exception during test - '{0}'", ex.Message));
 820            }
 821
 822            testing &= strategy != TestStrategy.FindFirstError;
 823          }
 824
 825          if (testing && testData && this[entryIndex].IsFile) {
 826            if (resultHandler != null) {
 827              status.SetOperation(TestOperation.EntryData);
 828              resultHandler(status, null);
 829            }
 830
 831            var crc = new Crc32();
 832
 833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {
 834
 835              byte[] buffer = new byte[4096];
 836              long totalBytes = 0;
 837              int bytesRead;
 838              while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
 839                crc.Update(buffer, 0, bytesRead);
 840
 841                if (resultHandler != null) {
 842                  totalBytes += bytesRead;
 843                  status.SetBytesTested(totalBytes);
 844                  resultHandler(status, null);
 845                }
 846              }
 847            }
 848
 849            if (this[entryIndex].Crc != crc.Value) {
 850              status.AddError();
 851
 852              if (resultHandler != null) {
 853                resultHandler(status, "CRC mismatch");
 854              }
 855
 856              testing &= strategy != TestStrategy.FindFirstError;
 857            }
 858
 859            if ((this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 860              var helper = new ZipHelperStream(baseStream_);
 861              var data = new DescriptorData();
 862              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
 863              if (this[entryIndex].Crc != data.Crc) {
 864                status.AddError();
 865              }
 866
 867              if (this[entryIndex].CompressedSize != data.CompressedSize) {
 868                status.AddError();
 869              }
 870
 871              if (this[entryIndex].Size != data.Size) {
 872                status.AddError();
 873              }
 874            }
 875          }
 876
 877          if (resultHandler != null) {
 878            status.SetOperation(TestOperation.EntryComplete);
 879            resultHandler(status, null);
 880          }
 881
 882          entryIndex += 1;
 883        }
 884
 885        if (resultHandler != null) {
 886          status.SetOperation(TestOperation.MiscellaneousTests);
 887          resultHandler(status, null);
 888        }
 889
 890        // TODO: the 'Corrina Johns' test where local headers are missing from
 891        // the central directory.  They are therefore invisible to many archivers.
 892      } catch (Exception ex) {
 893        status.AddError();
 894
 895        if (resultHandler != null) {
 896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
 897        }
 898      }
 899
 900      if (resultHandler != null) {
 901        status.SetOperation(TestOperation.Complete);
 902        status.SetEntry(null);
 903        resultHandler(status, null);
 904      }
 905
 906      return (status.ErrorCount == 0);
 907    }
 908
 909    [Flags]
 910    enum HeaderTest
 911    {
 912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted
 913      Header = 0x02,     // Check that this header contents are valid
 914    }
 915
 916    /// <summary>
 917    /// Test a local header against that provided from the central directory
 918    /// </summary>
 919    /// <param name="entry">
 920    /// The entry to test against
 921    /// </param>
 922    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
 923    /// <returns>The offset of the entries data in the file</returns>
 924    long TestLocalHeader(ZipEntry entry, HeaderTest tests)
 925    {
 926      lock (baseStream_) {
 927        bool testHeader = (tests & HeaderTest.Header) != 0;
 928        bool testData = (tests & HeaderTest.Extract) != 0;
 929
 930        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
 931        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
 932          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)
 933        }
 934
 935        var extractVersion = (short)(ReadLEUshort() & 0x00ff);
 936        var localFlags = (short)ReadLEUshort();
 937        var compressionMethod = (short)ReadLEUshort();
 938        var fileTime = (short)ReadLEUshort();
 939        var fileDate = (short)ReadLEUshort();
 940        uint crcValue = ReadLEUint();
 941        long compressedSize = ReadLEUint();
 942        long size = ReadLEUint();
 943        int storedNameLength = ReadLEUshort();
 944        int extraDataLength = ReadLEUshort();
 945
 946        byte[] nameData = new byte[storedNameLength];
 947        StreamUtils.ReadFully(baseStream_, nameData);
 948
 949        byte[] extraData = new byte[extraDataLength];
 950        StreamUtils.ReadFully(baseStream_, extraData);
 951
 952        var localExtraData = new ZipExtraData(extraData);
 953
 954        // Extra data / zip64 checks
 955        if (localExtraData.Find(1)) {
 956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
 957          // and size or compressedSize = MaxValue, due to rogue creators.
 958
 959          size = localExtraData.ReadLong();
 960          compressedSize = localExtraData.ReadLong();
 961
 962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {
 963            // These may be valid if patched later
 964            if ((size != -1) && (size != entry.Size)) {
 965              throw new ZipException("Size invalid for descriptor");
 966            }
 967
 968            if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {
 969              throw new ZipException("Compressed size invalid for descriptor");
 970            }
 971          }
 972        } else {
 973          // No zip64 extra data but entry requires it.
 974          if ((extractVersion >= ZipConstants.VersionZip64) &&
 975            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) {
 976            throw new ZipException("Required Zip64 extended information missing");
 977          }
 978        }
 979
 980        if (testData) {
 981          if (entry.IsFile) {
 982            if (!entry.IsCompressionMethodSupported()) {
 983              throw new ZipException("Compression method not supported");
 984            }
 985
 986            if ((extractVersion > ZipConstants.VersionMadeBy)
 987              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64))) {
 988              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract
 989            }
 990
 991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance
 992              throw new ZipException("The library does not support the zip version required to extract this entry");
 993            }
 994          }
 995        }
 996
 997        if (testHeader) {
 998          if ((extractVersion <= 63) &&   // Ignore later versions as we dont know about them..
 999            (extractVersion != 10) &&
 1000            (extractVersion != 11) &&
 1001            (extractVersion != 20) &&
 1002            (extractVersion != 21) &&
 1003            (extractVersion != 25) &&
 1004            (extractVersion != 27) &&
 1005            (extractVersion != 45) &&
 1006            (extractVersion != 46) &&
 1007            (extractVersion != 50) &&
 1008            (extractVersion != 51) &&
 1009            (extractVersion != 52) &&
 1010            (extractVersion != 61) &&
 1011            (extractVersion != 62) &&
 1012            (extractVersion != 63)
 1013            ) {
 1014            throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersi
 1015          }
 1016
 1017          // Local entry flags dont have reserved bit set on.
 1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R
 1019            throw new ZipException("Reserved bit flags cannot be set.");
 1020          }
 1021
 1022          // Encryption requires extract version >= 20
 1023          if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) {
 1024            throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})
 1025          }
 1026
 1027          // Strong encryption requires encryption flag to be set and extract version >= 50.
 1028          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1029            if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) {
 1030              throw new ZipException("Strong encryption flag set but encryption flag is not set");
 1031            }
 1032
 1033            if (extractVersion < 50) {
 1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0
 1035            }
 1036          }
 1037
 1038          // Patched entries require extract version >= 27
 1039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {
 1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
 1041          }
 1042
 1043          // Central header flags match local entry flags.
 1044          if (localFlags != entry.Flags) {
 1045            throw new ZipException("Central header/local header flags mismatch");
 1046          }
 1047
 1048          // Central header compression method matches local entry
 1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {
 1050            throw new ZipException("Central header/local header compression method mismatch");
 1051          }
 1052
 1053          if (entry.Version != extractVersion) {
 1054            throw new ZipException("Extract version mismatch");
 1055          }
 1056
 1057          // Strong encryption and extract version match
 1058          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1059            if (extractVersion < 62) {
 1060              throw new ZipException("Strong encryption flag set but version not high enough");
 1061            }
 1062          }
 1063
 1064          if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) {
 1065            if ((fileTime != 0) || (fileDate != 0)) {
 1066              throw new ZipException("Header masked set but date/time values non-zero");
 1067            }
 1068          }
 1069
 1070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
 1071            if (crcValue != (uint)entry.Crc) {
 1072              throw new ZipException("Central header/local header crc mismatch");
 1073            }
 1074          }
 1075
 1076          // Crc valid for empty entry.
 1077          // This will also apply to streamed entries where size isnt known and the header cant be patched
 1078          if ((size == 0) && (compressedSize == 0)) {
 1079            if (crcValue != 0) {
 1080              throw new ZipException("Invalid CRC for empty entry");
 1081            }
 1082          }
 1083
 1084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str
 1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
 1086          if (entry.Name.Length > storedNameLength) {
 1087            throw new ZipException("File name length mismatch");
 1088          }
 1089
 1090          // Name data has already been read convert it and compare.
 1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);
 1092
 1093          // Central directory and local entry name match
 1094          if (localName != entry.Name) {
 1095            throw new ZipException("Central header and local header file name mismatch");
 1096          }
 1097
 1098          // Directories have zero actual size but can have compressed size
 1099          if (entry.IsDirectory) {
 1100            if (size > 0) {
 1101              throw new ZipException("Directory cannot have size");
 1102            }
 1103
 1104            // There may be other cases where the compressed size can be greater than this?
 1105            // If so until details are known we will be strict.
 1106            if (entry.IsCrypted) {
 1107              if (compressedSize > ZipConstants.CryptoHeaderSize + 2) {
 1108                throw new ZipException("Directory compressed size invalid");
 1109              }
 1110            } else if (compressedSize > 2) {
 1111              // When not compressed the directory size can validly be 2 bytes
 1112              // if the true size wasnt known when data was originally being written.
 1113              // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
 1114              throw new ZipException("Directory compressed size invalid");
 1115            }
 1116          }
 1117
 1118          if (!ZipNameTransform.IsValidName(localName, true)) {
 1119            throw new ZipException("Name is invalid");
 1120          }
 1121        }
 1122
 1123        // Tests that apply to both data and header.
 1124
 1125        // Size can be verified only if it is known in the local header.
 1126        // it will always be known in the central header.
 1127        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
 1128          ((size > 0 || compressedSize > 0) && entry.Size > 0)) {
 1129
 1130          if ((size != 0)
 1131            && (size != entry.Size)) {
 1132            throw new ZipException(
 1133              string.Format("Size mismatch between central header({0}) and local header({1})",
 1134                entry.Size, size));
 1135          }
 1136
 1137          if ((compressedSize != 0)
 1138            && (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) {
 1139            throw new ZipException(
 1140              string.Format("Compressed size mismatch between central header({0}) and local header({1})",
 1141              entry.CompressedSize, compressedSize));
 1142          }
 1143        }
 1144
 1145        int extraLength = storedNameLength + extraDataLength;
 1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
 1147      }
 1148    }
 1149
 1150    #endregion
 1151
 1152    #region Updating
 1153
 1154    const int DefaultBufferSize = 4096;
 1155
 1156    /// <summary>
 1157    /// The kind of update to apply.
 1158    /// </summary>
 1159    enum UpdateCommand
 1160    {
 1161      Copy,       // Copy original file contents.
 1162      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.
 1163      Add,        // Add a new file to the archive.
 1164    }
 1165
 1166    #region Properties
 1167    /// <summary>
 1168    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.
 1169    /// </summary>
 1170    public INameTransform NameTransform {
 1171      get {
 1172        return updateEntryFactory_.NameTransform;
 1173      }
 1174
 1175      set {
 1176        updateEntryFactory_.NameTransform = value;
 1177      }
 1178    }
 1179
 1180    /// <summary>
 1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values
 1182    /// during updates.
 1183    /// </summary>
 1184    public IEntryFactory EntryFactory {
 1185      get {
 1186        return updateEntryFactory_;
 1187      }
 1188
 1189      set {
 1190        if (value == null) {
 1191          updateEntryFactory_ = new ZipEntryFactory();
 1192        } else {
 1193          updateEntryFactory_ = value;
 1194        }
 1195      }
 1196    }
 1197
 1198    /// <summary>
 1199    /// Get /set the buffer size to be used when updating this zip file.
 1200    /// </summary>
 1201    public int BufferSize {
 1202      get { return bufferSize_; }
 1203      set {
 1204        if (value < 1024) {
 1205          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");
 1206        }
 1207
 1208        if (bufferSize_ != value) {
 1209          bufferSize_ = value;
 1210          copyBuffer_ = null;
 1211        }
 1212      }
 1213    }
 1214
 1215    /// <summary>
 1216    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.
 1217    /// </summary>
 1218    public bool IsUpdating {
 1219      get { return updates_ != null; }
 1220    }
 1221
 1222    /// <summary>
 1223    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
 1224    /// </summary>
 1225    public UseZip64 UseZip64 {
 1226      get { return useZip64_; }
 1227      set { useZip64_ = value; }
 1228    }
 1229
 1230    #endregion
 1231
 1232    #region Immediate updating
 1233    //    TBD: Direct form of updating
 1234    //
 1235    //    public void Update(IEntryMatcher deleteMatcher)
 1236    //    {
 1237    //    }
 1238    //
 1239    //    public void Update(IScanner addScanner)
 1240    //    {
 1241    //    }
 1242    #endregion
 1243
 1244    #region Deferred Updating
 1245    /// <summary>
 1246    /// Begin updating this <see cref="ZipFile"/> archive.
 1247    /// </summary>
 1248    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p
 1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param
 1250    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1251    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>
 1252    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1253    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)
 1254    {
 1255      if (archiveStorage == null) {
 1256        throw new ArgumentNullException(nameof(archiveStorage));
 1257      }
 1258
 1259      if (dataSource == null) {
 1260        throw new ArgumentNullException(nameof(dataSource));
 1261      }
 1262
 1263      if (isDisposed_) {
 1264        throw new ObjectDisposedException("ZipFile");
 1265      }
 1266
 1267      if (IsEmbeddedArchive) {
 1268        throw new ZipException("Cannot update embedded/SFX archives");
 1269      }
 1270
 1271      archiveStorage_ = archiveStorage;
 1272      updateDataSource_ = dataSource;
 1273
 1274      // NOTE: the baseStream_ may not currently support writing or seeking.
 1275
 1276      updateIndex_ = new Hashtable();
 1277
 1278      updates_ = new ArrayList(entries_.Length);
 1279      foreach (ZipEntry entry in entries_) {
 1280        int index = updates_.Add(new ZipUpdate(entry));
 1281        updateIndex_.Add(entry.Name, index);
 1282      }
 1283
 1284      // We must sort by offset before using offset's calculated sizes
 1285      updates_.Sort(new UpdateComparer());
 1286
 1287      int idx = 0;
 1288      foreach (ZipUpdate update in updates_) {
 1289        //If last entry, there is no next entry offset to use
 1290        if (idx == updates_.Count - 1)
 1291          break;
 1292
 1293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;
 1294        idx++;
 1295      }
 1296      updateCount_ = updates_.Count;
 1297
 1298      contentsEdited_ = false;
 1299      commentEdited_ = false;
 1300      newComment_ = null;
 1301    }
 1302
 1303    /// <summary>
 1304    /// Begin updating to this <see cref="ZipFile"/> archive.
 1305    /// </summary>
 1306    /// <param name="archiveStorage">The storage to use during the update.</param>
 1307    public void BeginUpdate(IArchiveStorage archiveStorage)
 1308    {
 1309      BeginUpdate(archiveStorage, new DynamicDiskDataSource());
 1310    }
 1311
 1312    /// <summary>
 1313    /// Begin updating this <see cref="ZipFile"/> archive.
 1314    /// </summary>
 1315    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>
 1316    /// <seealso cref="CommitUpdate"></seealso>
 1317    /// <seealso cref="AbortUpdate"></seealso>
 1318    public void BeginUpdate()
 1319    {
 1320      if (Name == null) {
 1321        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());
 1322      } else {
 1323        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());
 1324      }
 1325    }
 1326
 1327    /// <summary>
 1328    /// Commit current updates, updating this archive.
 1329    /// </summary>
 1330    /// <seealso cref="BeginUpdate()"></seealso>
 1331    /// <seealso cref="AbortUpdate"></seealso>
 1332    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1333    public void CommitUpdate()
 1334    {
 1335      if (isDisposed_) {
 1336        throw new ObjectDisposedException("ZipFile");
 1337      }
 1338
 1339      CheckUpdating();
 1340
 1341      try {
 1342        updateIndex_.Clear();
 1343        updateIndex_ = null;
 1344
 1345        if (contentsEdited_) {
 1346          RunUpdates();
 1347        } else if (commentEdited_) {
 1348          UpdateCommentOnly();
 1349        } else {
 1350          // Create an empty archive if none existed originally.
 1351          if (entries_.Length == 0) {
 1352            byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 1353            using (ZipHelperStream zhs = new ZipHelperStream(baseStream_)) {
 1354              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
 1355            }
 1356          }
 1357        }
 1358
 1359      } finally {
 1360        PostUpdateCleanup();
 1361      }
 1362    }
 1363
 1364    /// <summary>
 1365    /// Abort updating leaving the archive unchanged.
 1366    /// </summary>
 1367    /// <seealso cref="BeginUpdate()"></seealso>
 1368    /// <seealso cref="CommitUpdate"></seealso>
 1369    public void AbortUpdate()
 1370    {
 1371      PostUpdateCleanup();
 1372    }
 1373
 1374    /// <summary>
 1375    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.
 1376    /// </summary>
 1377    /// <param name="comment">The comment to record.</param>
 1378    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1379    public void SetComment(string comment)
 1380    {
 1381      if (isDisposed_) {
 1382        throw new ObjectDisposedException("ZipFile");
 1383      }
 1384
 1385      CheckUpdating();
 1386
 1387      newComment_ = new ZipString(comment);
 1388
 1389      if (newComment_.RawLength > 0xffff) {
 1390        newComment_ = null;
 1391        throw new ZipException("Comment length exceeds maximum - 65535");
 1392      }
 1393
 1394      // We dont take account of the original and current comment appearing to be the same
 1395      // as encoding may be different.
 1396      commentEdited_ = true;
 1397    }
 1398
 1399    #endregion
 1400
 1401    #region Adding Entries
 1402
 1403    void AddUpdate(ZipUpdate update)
 1404    {
 1405      contentsEdited_ = true;
 1406
 1407      int index = FindExistingUpdate(update.Entry.Name);
 1408
 1409      if (index >= 0) {
 1410        if (updates_[index] == null) {
 1411          updateCount_ += 1;
 1412        }
 1413
 1414        // Direct replacement is faster than delete and add.
 1415        updates_[index] = update;
 1416      } else {
 1417        index = updates_.Add(update);
 1418        updateCount_ += 1;
 1419        updateIndex_.Add(update.Entry.Name, index);
 1420      }
 1421    }
 1422
 1423    /// <summary>
 1424    /// Add a new entry to the archive.
 1425    /// </summary>
 1426    /// <param name="fileName">The name of the file to add.</param>
 1427    /// <param name="compressionMethod">The compression method to use.</param>
 1428    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>
 1429    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1430    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1431    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>
 1432    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText)
 1433    {
 1434      if (fileName == null) {
 1435        throw new ArgumentNullException(nameof(fileName));
 1436      }
 1437
 1438      if (isDisposed_) {
 1439        throw new ObjectDisposedException("ZipFile");
 1440      }
 1441
 1442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1444      }
 1445
 1446      CheckUpdating();
 1447      contentsEdited_ = true;
 1448
 1449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1450      entry.IsUnicodeText = useUnicodeText;
 1451      entry.CompressionMethod = compressionMethod;
 1452
 1453      AddUpdate(new ZipUpdate(fileName, entry));
 1454    }
 1455
 1456    /// <summary>
 1457    /// Add a new entry to the archive.
 1458    /// </summary>
 1459    /// <param name="fileName">The name of the file to add.</param>
 1460    /// <param name="compressionMethod">The compression method to use.</param>
 1461    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>
 1462    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>
 1463    public void Add(string fileName, CompressionMethod compressionMethod)
 1464    {
 1465      if (fileName == null) {
 1466        throw new ArgumentNullException(nameof(fileName));
 1467      }
 1468
 1469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1471      }
 1472
 1473      CheckUpdating();
 1474      contentsEdited_ = true;
 1475
 1476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1477      entry.CompressionMethod = compressionMethod;
 1478      AddUpdate(new ZipUpdate(fileName, entry));
 1479    }
 1480
 1481    /// <summary>
 1482    /// Add a file to the archive.
 1483    /// </summary>
 1484    /// <param name="fileName">The name of the file to add.</param>
 1485    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1486    public void Add(string fileName)
 1487    {
 1488      if (fileName == null) {
 1489        throw new ArgumentNullException(nameof(fileName));
 1490      }
 1491
 1492      CheckUpdating();
 1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));
 1494    }
 1495
 1496    /// <summary>
 1497    /// Add a file to the archive.
 1498    /// </summary>
 1499    /// <param name="fileName">The name of the file to add.</param>
 1500    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>
 1501    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1502    public void Add(string fileName, string entryName)
 1503    {
 1504      if (fileName == null) {
 1505        throw new ArgumentNullException(nameof(fileName));
 1506      }
 1507
 1508      if (entryName == null) {
 1509        throw new ArgumentNullException(nameof(entryName));
 1510      }
 1511
 1512      CheckUpdating();
 1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));
 1514    }
 1515
 1516
 1517    /// <summary>
 1518    /// Add a file entry with data.
 1519    /// </summary>
 1520    /// <param name="dataSource">The source of the data for this entry.</param>
 1521    /// <param name="entryName">The name to give to the entry.</param>
 1522    public void Add(IStaticDataSource dataSource, string entryName)
 1523    {
 1524      if (dataSource == null) {
 1525        throw new ArgumentNullException(nameof(dataSource));
 1526      }
 1527
 1528      if (entryName == null) {
 1529        throw new ArgumentNullException(nameof(entryName));
 1530      }
 1531
 1532      CheckUpdating();
 1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));
 1534    }
 1535
 1536    /// <summary>
 1537    /// Add a file entry with data.
 1538    /// </summary>
 1539    /// <param name="dataSource">The source of the data for this entry.</param>
 1540    /// <param name="entryName">The name to give to the entry.</param>
 1541    /// <param name="compressionMethod">The compression method to use.</param>
 1542    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 1543    {
 1544      if (dataSource == null) {
 1545        throw new ArgumentNullException(nameof(dataSource));
 1546      }
 1547
 1548      if (entryName == null) {
 1549        throw new ArgumentNullException(nameof(entryName));
 1550      }
 1551
 1552      CheckUpdating();
 1553
 1554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1555      entry.CompressionMethod = compressionMethod;
 1556
 1557      AddUpdate(new ZipUpdate(dataSource, entry));
 1558    }
 1559
 1560    /// <summary>
 1561    /// Add a file entry with data.
 1562    /// </summary>
 1563    /// <param name="dataSource">The source of the data for this entry.</param>
 1564    /// <param name="entryName">The name to give to the entry.</param>
 1565    /// <param name="compressionMethod">The compression method to use.</param>
 1566    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>
 1567    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode
 1568    {
 1569      if (dataSource == null) {
 1570        throw new ArgumentNullException(nameof(dataSource));
 1571      }
 1572
 1573      if (entryName == null) {
 1574        throw new ArgumentNullException(nameof(entryName));
 1575      }
 1576
 1577      CheckUpdating();
 1578
 1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1580      entry.IsUnicodeText = useUnicodeText;
 1581      entry.CompressionMethod = compressionMethod;
 1582
 1583      AddUpdate(new ZipUpdate(dataSource, entry));
 1584    }
 1585
 1586    /// <summary>
 1587    /// Add a <see cref="ZipEntry"/> that contains no data.
 1588    /// </summary>
 1589    /// <param name="entry">The entry to add.</param>
 1590    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
 1591    public void Add(ZipEntry entry)
 1592    {
 1593      if (entry == null) {
 1594        throw new ArgumentNullException(nameof(entry));
 1595      }
 1596
 1597      CheckUpdating();
 1598
 1599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {
 1600        throw new ZipException("Entry cannot have any data");
 1601      }
 1602
 1603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
 1604    }
 1605
 1606    /// <summary>
 1607    /// Add a directory entry to the archive.
 1608    /// </summary>
 1609    /// <param name="directoryName">The directory to add.</param>
 1610    public void AddDirectory(string directoryName)
 1611    {
 1612      if (directoryName == null) {
 1613        throw new ArgumentNullException(nameof(directoryName));
 1614      }
 1615
 1616      CheckUpdating();
 1617
 1618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);
 1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));
 1620    }
 1621
 1622    #endregion
 1623
 1624    #region Modifying Entries
 1625    /* Modify not yet ready for public consumption.
 1626       Direct modification of an entry should not overwrite original data before its read.
 1627       Safe mode is trivial in this sense.
 1628        public void Modify(ZipEntry original, ZipEntry updated)
 1629        {
 1630          if ( original == null ) {
 1631            throw new ArgumentNullException("original");
 1632          }
 1633
 1634          if ( updated == null ) {
 1635            throw new ArgumentNullException("updated");
 1636          }
 1637
 1638          CheckUpdating();
 1639          contentsEdited_ = true;
 1640          updates_.Add(new ZipUpdate(original, updated));
 1641        }
 1642    */
 1643    #endregion
 1644
 1645    #region Deleting Entries
 1646    /// <summary>
 1647    /// Delete an entry by name
 1648    /// </summary>
 1649    /// <param name="fileName">The filename to delete</param>
 1650    /// <returns>True if the entry was found and deleted; false otherwise.</returns>
 1651    public bool Delete(string fileName)
 1652    {
 1653      if (fileName == null) {
 1654        throw new ArgumentNullException(nameof(fileName));
 1655      }
 1656
 1657      CheckUpdating();
 1658
 1659      bool result = false;
 1660      int index = FindExistingUpdate(fileName);
 1661      if ((index >= 0) && (updates_[index] != null)) {
 1662        result = true;
 1663        contentsEdited_ = true;
 1664        updates_[index] = null;
 1665        updateCount_ -= 1;
 1666      } else {
 1667        throw new ZipException("Cannot find entry to delete");
 1668      }
 1669      return result;
 1670    }
 1671
 1672    /// <summary>
 1673    /// Delete a <see cref="ZipEntry"/> from the archive.
 1674    /// </summary>
 1675    /// <param name="entry">The entry to delete.</param>
 1676    public void Delete(ZipEntry entry)
 1677    {
 1678      if (entry == null) {
 1679        throw new ArgumentNullException(nameof(entry));
 1680      }
 1681
 1682      CheckUpdating();
 1683
 1684      int index = FindExistingUpdate(entry);
 1685      if (index >= 0) {
 1686        contentsEdited_ = true;
 1687        updates_[index] = null;
 1688        updateCount_ -= 1;
 1689      } else {
 1690        throw new ZipException("Cannot find entry to delete");
 1691      }
 1692    }
 1693
 1694    #endregion
 1695
 1696    #region Update Support
 1697
 1698    #region Writing Values/Headers
 1699    void WriteLEShort(int value)
 1700    {
 1701      baseStream_.WriteByte((byte)(value & 0xff));
 1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));
 1703    }
 1704
 1705    /// <summary>
 1706    /// Write an unsigned short in little endian byte order.
 1707    /// </summary>
 1708    void WriteLEUshort(ushort value)
 1709    {
 1710      baseStream_.WriteByte((byte)(value & 0xff));
 1711      baseStream_.WriteByte((byte)(value >> 8));
 1712    }
 1713
 1714    /// <summary>
 1715    /// Write an int in little endian byte order.
 1716    /// </summary>
 1717    void WriteLEInt(int value)
 1718    {
 1719      WriteLEShort(value & 0xffff);
 1720      WriteLEShort(value >> 16);
 1721    }
 1722
 1723    /// <summary>
 1724    /// Write an unsigned int in little endian byte order.
 1725    /// </summary>
 1726    void WriteLEUint(uint value)
 1727    {
 1728      WriteLEUshort((ushort)(value & 0xffff));
 1729      WriteLEUshort((ushort)(value >> 16));
 1730    }
 1731
 1732    /// <summary>
 1733    /// Write a long in little endian byte order.
 1734    /// </summary>
 1735    void WriteLeLong(long value)
 1736    {
 1737      WriteLEInt((int)(value & 0xffffffff));
 1738      WriteLEInt((int)(value >> 32));
 1739    }
 1740
 1741    void WriteLEUlong(ulong value)
 1742    {
 1743      WriteLEUint((uint)(value & 0xffffffff));
 1744      WriteLEUint((uint)(value >> 32));
 1745    }
 1746
 1747    void WriteLocalEntryHeader(ZipUpdate update)
 1748    {
 1749      ZipEntry entry = update.OutEntry;
 1750
 1751      // TODO: Local offset will require adjusting for multi-disk zip files.
 1752      entry.Offset = baseStream_.Position;
 1753
 1754      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
 1755      if (update.Command != UpdateCommand.Copy) {
 1756        if (entry.CompressionMethod == CompressionMethod.Deflated) {
 1757          if (entry.Size == 0) {
 1758            // No need to compress - no data.
 1759            entry.CompressedSize = entry.Size;
 1760            entry.Crc = 0;
 1761            entry.CompressionMethod = CompressionMethod.Stored;
 1762          }
 1763        } else if (entry.CompressionMethod == CompressionMethod.Stored) {
 1764          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
 1765        }
 1766
 1767        if (HaveKeys) {
 1768          entry.IsCrypted = true;
 1769          if (entry.Crc < 0) {
 1770            entry.Flags |= (int)GeneralBitFlags.Descriptor;
 1771          }
 1772        } else {
 1773          entry.IsCrypted = false;
 1774        }
 1775
 1776        switch (useZip64_) {
 1777          case UseZip64.Dynamic:
 1778            if (entry.Size < 0) {
 1779              entry.ForceZip64();
 1780            }
 1781            break;
 1782
 1783          case UseZip64.On:
 1784            entry.ForceZip64();
 1785            break;
 1786
 1787          case UseZip64.Off:
 1788            // Do nothing.  The entry itself may be using Zip64 independantly.
 1789            break;
 1790        }
 1791      }
 1792
 1793      // Write the local file header
 1794      WriteLEInt(ZipConstants.LocalHeaderSignature);
 1795
 1796      WriteLEShort(entry.Version);
 1797      WriteLEShort(entry.Flags);
 1798
 1799      WriteLEShort((byte)entry.CompressionMethod);
 1800      WriteLEInt((int)entry.DosTime);
 1801
 1802      if (!entry.HasCrc) {
 1803        // Note patch address for updating CRC later.
 1804        update.CrcPatchOffset = baseStream_.Position;
 1805        WriteLEInt((int)0);
 1806      } else {
 1807        WriteLEInt(unchecked((int)entry.Crc));
 1808      }
 1809
 1810      if (entry.LocalHeaderRequiresZip64) {
 1811        WriteLEInt(-1);
 1812        WriteLEInt(-1);
 1813      } else {
 1814        if ((entry.CompressedSize < 0) || (entry.Size < 0)) {
 1815          update.SizePatchOffset = baseStream_.Position;
 1816        }
 1817
 1818        WriteLEInt((int)entry.CompressedSize);
 1819        WriteLEInt((int)entry.Size);
 1820      }
 1821
 1822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1823
 1824      if (name.Length > 0xFFFF) {
 1825        throw new ZipException("Entry name too long.");
 1826      }
 1827
 1828      var ed = new ZipExtraData(entry.ExtraData);
 1829
 1830      if (entry.LocalHeaderRequiresZip64) {
 1831        ed.StartNewEntry();
 1832
 1833        // Local entry header always includes size and compressed size.
 1834        // NOTE the order of these fields is reversed when compared to the normal headers!
 1835        ed.AddLeLong(entry.Size);
 1836        ed.AddLeLong(entry.CompressedSize);
 1837        ed.AddNewEntry(1);
 1838      } else {
 1839        ed.Delete(1);
 1840      }
 1841
 1842      entry.ExtraData = ed.GetEntryData();
 1843
 1844      WriteLEShort(name.Length);
 1845      WriteLEShort(entry.ExtraData.Length);
 1846
 1847      if (name.Length > 0) {
 1848        baseStream_.Write(name, 0, name.Length);
 1849      }
 1850
 1851      if (entry.LocalHeaderRequiresZip64) {
 1852        if (!ed.Find(1)) {
 1853          throw new ZipException("Internal error cannot find extra data");
 1854        }
 1855
 1856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
 1857      }
 1858
 1859      if (entry.ExtraData.Length > 0) {
 1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
 1861      }
 1862    }
 1863
 1864    int WriteCentralDirectoryHeader(ZipEntry entry)
 1865    {
 1866      if (entry.CompressedSize < 0) {
 1867        throw new ZipException("Attempt to write central directory entry with unknown csize");
 1868      }
 1869
 1870      if (entry.Size < 0) {
 1871        throw new ZipException("Attempt to write central directory entry with unknown size");
 1872      }
 1873
 1874      if (entry.Crc < 0) {
 1875        throw new ZipException("Attempt to write central directory entry with unknown crc");
 1876      }
 1877
 1878      // Write the central file header
 1879      WriteLEInt(ZipConstants.CentralHeaderSignature);
 1880
 1881      // Version made by
 1882      WriteLEShort(ZipConstants.VersionMadeBy);
 1883
 1884      // Version required to extract
 1885      WriteLEShort(entry.Version);
 1886
 1887      WriteLEShort(entry.Flags);
 1888
 1889      unchecked {
 1890        WriteLEShort((byte)entry.CompressionMethod);
 1891        WriteLEInt((int)entry.DosTime);
 1892        WriteLEInt((int)entry.Crc);
 1893      }
 1894
 1895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {
 1896        WriteLEInt(-1);
 1897      } else {
 1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
 1899      }
 1900
 1901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {
 1902        WriteLEInt(-1);
 1903      } else {
 1904        WriteLEInt((int)entry.Size);
 1905      }
 1906
 1907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1908
 1909      if (name.Length > 0xFFFF) {
 1910        throw new ZipException("Entry name is too long.");
 1911      }
 1912
 1913      WriteLEShort(name.Length);
 1914
 1915      // Central header extra data is different to local header version so regenerate.
 1916      var ed = new ZipExtraData(entry.ExtraData);
 1917
 1918      if (entry.CentralHeaderRequiresZip64) {
 1919        ed.StartNewEntry();
 1920
 1921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1922          ed.AddLeLong(entry.Size);
 1923        }
 1924
 1925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1926          ed.AddLeLong(entry.CompressedSize);
 1927        }
 1928
 1929        if (entry.Offset >= 0xffffffff) {
 1930          ed.AddLeLong(entry.Offset);
 1931        }
 1932
 1933        // Number of disk on which this file starts isnt supported and is never written here.
 1934        ed.AddNewEntry(1);
 1935      } else {
 1936        // Should have already be done when local header was added.
 1937        ed.Delete(1);
 1938      }
 1939
 1940      byte[] centralExtraData = ed.GetEntryData();
 1941
 1942      WriteLEShort(centralExtraData.Length);
 1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);
 1944
 1945      WriteLEShort(0);    // disk number
 1946      WriteLEShort(0);    // internal file attributes
 1947
 1948      // External file attributes...
 1949      if (entry.ExternalFileAttributes != -1) {
 1950        WriteLEInt(entry.ExternalFileAttributes);
 1951      } else {
 1952        if (entry.IsDirectory) {
 1953          WriteLEUint(16);
 1954        } else {
 1955          WriteLEUint(0);
 1956        }
 1957      }
 1958
 1959      if (entry.Offset >= 0xffffffff) {
 1960        WriteLEUint(0xffffffff);
 1961      } else {
 1962        WriteLEUint((uint)(int)entry.Offset);
 1963      }
 1964
 1965      if (name.Length > 0) {
 1966        baseStream_.Write(name, 0, name.Length);
 1967      }
 1968
 1969      if (centralExtraData.Length > 0) {
 1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
 1971      }
 1972
 1973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];
 1974
 1975      if (rawComment.Length > 0) {
 1976        baseStream_.Write(rawComment, 0, rawComment.Length);
 1977      }
 1978
 1979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
 1980    }
 1981    #endregion
 1982
 1983    void PostUpdateCleanup()
 1984    {
 1985      updateDataSource_ = null;
 1986      updates_ = null;
 1987      updateIndex_ = null;
 1988
 1989      if (archiveStorage_ != null) {
 1990        archiveStorage_.Dispose();
 1991        archiveStorage_ = null;
 1992      }
 1993    }
 1994
 1995    string GetTransformedFileName(string name)
 1996    {
 1997      INameTransform transform = NameTransform;
 1998      return (transform != null) ?
 1999        transform.TransformFile(name) :
 2000        name;
 2001    }
 2002
 2003    string GetTransformedDirectoryName(string name)
 2004    {
 2005      INameTransform transform = NameTransform;
 2006      return (transform != null) ?
 2007        transform.TransformDirectory(name) :
 2008        name;
 2009    }
 2010
 2011    /// <summary>
 2012    /// Get a raw memory buffer.
 2013    /// </summary>
 2014    /// <returns>Returns a raw memory buffer.</returns>
 2015    byte[] GetBuffer()
 2016    {
 2017      if (copyBuffer_ == null) {
 2018        copyBuffer_ = new byte[bufferSize_];
 2019      }
 2020      return copyBuffer_;
 2021    }
 2022
 2023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)
 2024    {
 2025      int bytesToCopy = GetDescriptorSize(update);
 2026
 2027      if (bytesToCopy > 0) {
 2028        byte[] buffer = GetBuffer();
 2029
 2030        while (bytesToCopy > 0) {
 2031          int readSize = Math.Min(buffer.Length, bytesToCopy);
 2032
 2033          int bytesRead = source.Read(buffer, 0, readSize);
 2034          if (bytesRead > 0) {
 2035            dest.Write(buffer, 0, bytesRead);
 2036            bytesToCopy -= bytesRead;
 2037          } else {
 2038            throw new ZipException("Unxpected end of stream");
 2039          }
 2040        }
 2041      }
 2042    }
 2043
 2044    void CopyBytes(ZipUpdate update, Stream destination, Stream source,
 2045      long bytesToCopy, bool updateCrc)
 2046    {
 2047      if (destination == source) {
 2048        throw new InvalidOperationException("Destination and source are the same");
 2049      }
 2050
 2051      // NOTE: Compressed size is updated elsewhere.
 2052      var crc = new Crc32();
 2053      byte[] buffer = GetBuffer();
 2054
 2055      long targetBytes = bytesToCopy;
 2056      long totalBytesRead = 0;
 2057
 2058      int bytesRead;
 2059      do {
 2060        int readSize = buffer.Length;
 2061
 2062        if (bytesToCopy < readSize) {
 2063          readSize = (int)bytesToCopy;
 2064        }
 2065
 2066        bytesRead = source.Read(buffer, 0, readSize);
 2067        if (bytesRead > 0) {
 2068          if (updateCrc) {
 2069            crc.Update(buffer, 0, bytesRead);
 2070          }
 2071          destination.Write(buffer, 0, bytesRead);
 2072          bytesToCopy -= bytesRead;
 2073          totalBytesRead += bytesRead;
 2074        }
 2075      }
 2076      while ((bytesRead > 0) && (bytesToCopy > 0));
 2077
 2078      if (totalBytesRead != targetBytes) {
 2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2080      }
 2081
 2082      if (updateCrc) {
 2083        update.OutEntry.Crc = crc.Value;
 2084      }
 2085    }
 2086
 2087    /// <summary>
 2088    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
 2089    /// </summary>
 2090    /// <param name="update">The update to get the size for.</param>
 2091    /// <returns>The descriptor size, zero if there isnt one.</returns>
 2092    int GetDescriptorSize(ZipUpdate update)
 2093    {
 2094      int result = 0;
 2095      if ((update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 2096        result = ZipConstants.DataDescriptorSize - 4;
 2097        if (update.Entry.LocalHeaderRequiresZip64) {
 2098          result = ZipConstants.Zip64DataDescriptorSize - 4;
 2099        }
 2100      }
 2101      return result;
 2102    }
 2103
 2104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
 2105    {
 2106      int bytesToCopy = GetDescriptorSize(update);
 2107
 2108      while (bytesToCopy > 0) {
 2109        var readSize = (int)bytesToCopy;
 2110        byte[] buffer = GetBuffer();
 2111
 2112        stream.Position = sourcePosition;
 2113        int bytesRead = stream.Read(buffer, 0, readSize);
 2114        if (bytesRead > 0) {
 2115          stream.Position = destinationPosition;
 2116          stream.Write(buffer, 0, bytesRead);
 2117          bytesToCopy -= bytesRead;
 2118          destinationPosition += bytesRead;
 2119          sourcePosition += bytesRead;
 2120        } else {
 2121          throw new ZipException("Unxpected end of stream");
 2122        }
 2123      }
 2124    }
 2125
 2126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou
 2127    {
 2128      long bytesToCopy = update.Entry.CompressedSize;
 2129
 2130      // NOTE: Compressed size is updated elsewhere.
 2131      var crc = new Crc32();
 2132      byte[] buffer = GetBuffer();
 2133
 2134      long targetBytes = bytesToCopy;
 2135      long totalBytesRead = 0;
 2136
 2137      int bytesRead;
 2138      do {
 2139        int readSize = buffer.Length;
 2140
 2141        if (bytesToCopy < readSize) {
 2142          readSize = (int)bytesToCopy;
 2143        }
 2144
 2145        stream.Position = sourcePosition;
 2146        bytesRead = stream.Read(buffer, 0, readSize);
 2147        if (bytesRead > 0) {
 2148          if (updateCrc) {
 2149            crc.Update(buffer, 0, bytesRead);
 2150          }
 2151          stream.Position = destinationPosition;
 2152          stream.Write(buffer, 0, bytesRead);
 2153
 2154          destinationPosition += bytesRead;
 2155          sourcePosition += bytesRead;
 2156          bytesToCopy -= bytesRead;
 2157          totalBytesRead += bytesRead;
 2158        }
 2159      }
 2160      while ((bytesRead > 0) && (bytesToCopy > 0));
 2161
 2162      if (totalBytesRead != targetBytes) {
 2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2164      }
 2165
 2166      if (updateCrc) {
 2167        update.OutEntry.Crc = crc.Value;
 2168      }
 2169    }
 2170
 2171    int FindExistingUpdate(ZipEntry entry)
 2172    {
 2173      int result = -1;
 2174      string convertedName = GetTransformedFileName(entry.Name);
 2175
 2176      if (updateIndex_.ContainsKey(convertedName)) {
 2177        result = (int)updateIndex_[convertedName];
 2178      }
 2179      /*
 2180            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2181            // for CF?
 2182            for (int index = 0; index < updates_.Count; ++index)
 2183            {
 2184              ZipUpdate zu = ( ZipUpdate )updates_[index];
 2185              if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
 2186                (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
 2187                result = index;
 2188                break;
 2189              }
 2190            }
 2191       */
 2192      return result;
 2193    }
 2194
 2195    int FindExistingUpdate(string fileName)
 2196    {
 2197      int result = -1;
 2198
 2199      string convertedName = GetTransformedFileName(fileName);
 2200
 2201      if (updateIndex_.ContainsKey(convertedName)) {
 2202        result = (int)updateIndex_[convertedName];
 2203      }
 2204
 2205      /*
 2206            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2207            // for CF?
 2208            for ( int index = 0; index < updates_.Count; ++index ) {
 2209              if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,
 2210                true, CultureInfo.InvariantCulture) == 0 ) {
 2211                result = index;
 2212                break;
 2213              }
 2214            }
 2215       */
 2216
 2217      return result;
 2218    }
 2219
 2220    /// <summary>
 2221    /// Get an output stream for the specified <see cref="ZipEntry"/>
 2222    /// </summary>
 2223    /// <param name="entry">The entry to get an output stream for.</param>
 2224    /// <returns>The output stream obtained for the entry.</returns>
 2225    Stream GetOutputStream(ZipEntry entry)
 2226    {
 2227      Stream result = baseStream_;
 2228
 2229      if (entry.IsCrypted == true) {
 2230        result = CreateAndInitEncryptionStream(result, entry);
 2231      }
 2232
 2233      switch (entry.CompressionMethod) {
 2234        case CompressionMethod.Stored:
 2235          result = new UncompressedStream(result);
 2236          break;
 2237
 2238        case CompressionMethod.Deflated:
 2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));
 2240          dos.IsStreamOwner = false;
 2241          result = dos;
 2242          break;
 2243
 2244        default:
 2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);
 2246      }
 2247      return result;
 2248    }
 2249
 2250    void AddEntry(ZipFile workFile, ZipUpdate update)
 2251    {
 2252      Stream source = null;
 2253
 2254      if (update.Entry.IsFile) {
 2255        source = update.GetSource();
 2256
 2257        if (source == null) {
 2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);
 2259        }
 2260      }
 2261
 2262      if (source != null) {
 2263        using (source) {
 2264          long sourceStreamLength = source.Length;
 2265          if (update.OutEntry.Size < 0) {
 2266            update.OutEntry.Size = sourceStreamLength;
 2267          } else {
 2268            // Check for errant entries.
 2269            if (update.OutEntry.Size != sourceStreamLength) {
 2270              throw new ZipException("Entry size/stream size mismatch");
 2271            }
 2272          }
 2273
 2274          workFile.WriteLocalEntryHeader(update);
 2275
 2276          long dataStart = workFile.baseStream_.Position;
 2277
 2278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2279            CopyBytes(update, output, source, sourceStreamLength, true);
 2280          }
 2281
 2282          long dataEnd = workFile.baseStream_.Position;
 2283          update.OutEntry.CompressedSize = dataEnd - dataStart;
 2284
 2285          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor) {
 2286            var helper = new ZipHelperStream(workFile.baseStream_);
 2287            helper.WriteDataDescriptor(update.OutEntry);
 2288          }
 2289        }
 2290      } else {
 2291        workFile.WriteLocalEntryHeader(update);
 2292        update.OutEntry.CompressedSize = 0;
 2293      }
 2294
 2295    }
 2296
 2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)
 2298    {
 2299      workFile.WriteLocalEntryHeader(update);
 2300      long dataStart = workFile.baseStream_.Position;
 2301
 2302      // TODO: This is slow if the changes don't effect the data!!
 2303      if (update.Entry.IsFile && (update.Filename != null)) {
 2304        using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2305          using (Stream source = this.GetInputStream(update.Entry)) {
 2306            CopyBytes(update, output, source, source.Length, true);
 2307          }
 2308        }
 2309      }
 2310
 2311      long dataEnd = workFile.baseStream_.Position;
 2312      update.Entry.CompressedSize = dataEnd - dataStart;
 2313    }
 2314
 2315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)
 2316    {
 2317      bool skipOver = false || update.Entry.Offset == destinationPosition;
 2318
 2319      if (!skipOver) {
 2320        baseStream_.Position = destinationPosition;
 2321        workFile.WriteLocalEntryHeader(update);
 2322        destinationPosition = baseStream_.Position;
 2323      }
 2324
 2325      long sourcePosition = 0;
 2326
 2327      const int NameLengthOffset = 26;
 2328
 2329      // TODO: Add base for SFX friendly handling
 2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2331
 2332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2333
 2334      // Clumsy way of handling retrieving the original name and extra data length for now.
 2335      // TODO: Stop re-reading name and data length in CopyEntryDirect.
 2336      uint nameLength = ReadLEUshort();
 2337      uint extraLength = ReadLEUshort();
 2338
 2339      sourcePosition = baseStream_.Position + nameLength + extraLength;
 2340
 2341      if (skipOver) {
 2342        if (update.OffsetBasedSize != -1)
 2343          destinationPosition += update.OffsetBasedSize;
 2344        else
 2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar
 2346          // WinZip produces a warning on these entries:
 2347          // "caution: value of lrec.csize (compressed size) changed from ..."
 2348          destinationPosition +=
 2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size
 2350            update.Entry.CompressedSize + GetDescriptorSize(update);
 2351      } else {
 2352        if (update.Entry.CompressedSize > 0) {
 2353          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition);
 2354        }
 2355        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
 2356      }
 2357    }
 2358
 2359    void CopyEntry(ZipFile workFile, ZipUpdate update)
 2360    {
 2361      workFile.WriteLocalEntryHeader(update);
 2362
 2363      if (update.Entry.CompressedSize > 0) {
 2364        const int NameLengthOffset = 26;
 2365
 2366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2367
 2368        // TODO: This wont work for SFX files!
 2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2370
 2371        uint nameLength = ReadLEUshort();
 2372        uint extraLength = ReadLEUshort();
 2373
 2374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);
 2375
 2376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
 2377      }
 2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
 2379    }
 2380
 2381    void Reopen(Stream source)
 2382    {
 2383      if (source == null) {
 2384        throw new ZipException("Failed to reopen archive - no source");
 2385      }
 2386
 2387      isNewArchive_ = false;
 2388      baseStream_ = source;
 2389      ReadEntries();
 2390    }
 2391
 2392    void Reopen()
 2393    {
 2394      if (Name == null) {
 2395        throw new InvalidOperationException("Name is not known cannot Reopen");
 2396      }
 2397
 2398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));
 2399    }
 2400
 2401    void UpdateCommentOnly()
 2402    {
 2403      long baseLength = baseStream_.Length;
 2404
 2405      ZipHelperStream updateFile = null;
 2406
 2407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
 2409        updateFile = new ZipHelperStream(copyStream);
 2410        updateFile.IsStreamOwner = true;
 2411
 2412        baseStream_.Close();
 2413        baseStream_ = null;
 2414      } else {
 2415        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2416          // TODO: archiveStorage wasnt originally intended for this use.
 2417          // Need to revisit this to tidy up handling as archive storage currently doesnt
 2418          // handle the original stream well.
 2419          // The problem is when using an existing zip archive with an in memory archive storage.
 2420          // The open stream wont support writing but the memory storage should open the same file not an in memory one.
 2421
 2422          // Need to tidy up the archive storage interface and contract basically.
 2423          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);
 2424          updateFile = new ZipHelperStream(baseStream_);
 2425        } else {
 2426          baseStream_.Close();
 2427          baseStream_ = null;
 2428          updateFile = new ZipHelperStream(Name);
 2429        }
 2430      }
 2431
 2432      using (updateFile) {
 2433        long locatedCentralDirOffset =
 2434          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2435                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2436        if (locatedCentralDirOffset < 0) {
 2437          throw new ZipException("Cannot find central directory");
 2438        }
 2439
 2440        const int CentralHeaderCommentSizeOffset = 16;
 2441        updateFile.Position += CentralHeaderCommentSizeOffset;
 2442
 2443        byte[] rawComment = newComment_.RawComment;
 2444
 2445        updateFile.WriteLEShort(rawComment.Length);
 2446        updateFile.Write(rawComment, 0, rawComment.Length);
 2447        updateFile.SetLength(updateFile.Position);
 2448      }
 2449
 2450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2452      } else {
 2453        ReadEntries();
 2454      }
 2455    }
 2456
 2457    /// <summary>
 2458    /// Class used to sort updates.
 2459    /// </summary>
 2460    class UpdateComparer : IComparer
 2461    {
 2462      /// <summary>
 2463      /// Compares two objects and returns a value indicating whether one is
 2464      /// less than, equal to or greater than the other.
 2465      /// </summary>
 2466      /// <param name="x">First object to compare</param>
 2467      /// <param name="y">Second object to compare.</param>
 2468      /// <returns>Compare result.</returns>
 2469      public int Compare(
 2470        object x,
 2471        object y)
 2472      {
 2473        var zx = x as ZipUpdate;
 2474        var zy = y as ZipUpdate;
 2475
 2476        int result;
 2477
 2478        if (zx == null) {
 2479          if (zy == null) {
 2480            result = 0;
 2481          } else {
 2482            result = -1;
 2483          }
 2484        } else if (zy == null) {
 2485          result = 1;
 2486        } else {
 2487          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;
 2488          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;
 2489
 2490          result = xCmdValue - yCmdValue;
 2491          if (result == 0) {
 2492            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;
 2493            if (offsetDiff < 0) {
 2494              result = -1;
 2495            } else if (offsetDiff == 0) {
 2496              result = 0;
 2497            } else {
 2498              result = 1;
 2499            }
 2500          }
 2501        }
 2502        return result;
 2503      }
 2504    }
 2505
 2506    void RunUpdates()
 2507    {
 2508      long sizeEntries = 0;
 2509      long endOfStream = 0;
 2510      bool directUpdate = false;
 2511      long destinationPosition = 0; // NOT SFX friendly
 2512
 2513      ZipFile workFile;
 2514
 2515      if (IsNewArchive) {
 2516        workFile = this;
 2517        workFile.baseStream_.Position = 0;
 2518        directUpdate = true;
 2519      } else if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2520        workFile = this;
 2521        workFile.baseStream_.Position = 0;
 2522        directUpdate = true;
 2523
 2524        // Sort the updates by offset within copies/modifies, then adds.
 2525        // This ensures that data required by copies will not be overwritten.
 2526        updates_.Sort(new UpdateComparer());
 2527      } else {
 2528        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
 2529        workFile.UseZip64 = UseZip64;
 2530
 2531        if (key != null) {
 2532          workFile.key = (byte[])key.Clone();
 2533        }
 2534      }
 2535
 2536      try {
 2537        foreach (ZipUpdate update in updates_) {
 2538          if (update != null) {
 2539            switch (update.Command) {
 2540              case UpdateCommand.Copy:
 2541                if (directUpdate) {
 2542                  CopyEntryDirect(workFile, update, ref destinationPosition);
 2543                } else {
 2544                  CopyEntry(workFile, update);
 2545                }
 2546                break;
 2547
 2548              case UpdateCommand.Modify:
 2549                // TODO: Direct modifying of an entry will take some legwork.
 2550                ModifyEntry(workFile, update);
 2551                break;
 2552
 2553              case UpdateCommand.Add:
 2554                if (!IsNewArchive && directUpdate) {
 2555                  workFile.baseStream_.Position = destinationPosition;
 2556                }
 2557
 2558                AddEntry(workFile, update);
 2559
 2560                if (directUpdate) {
 2561                  destinationPosition = workFile.baseStream_.Position;
 2562                }
 2563                break;
 2564            }
 2565          }
 2566        }
 2567
 2568        if (!IsNewArchive && directUpdate) {
 2569          workFile.baseStream_.Position = destinationPosition;
 2570        }
 2571
 2572        long centralDirOffset = workFile.baseStream_.Position;
 2573
 2574        foreach (ZipUpdate update in updates_) {
 2575          if (update != null) {
 2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
 2577          }
 2578        }
 2579
 2580        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 2581        using (ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_)) {
 2582          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);
 2583        }
 2584
 2585        endOfStream = workFile.baseStream_.Position;
 2586
 2587        // And now patch entries...
 2588        foreach (ZipUpdate update in updates_) {
 2589          if (update != null) {
 2590            // If the size of the entry is zero leave the crc as 0 as well.
 2591            // The calculated crc will be all bits on...
 2592            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {
 2593              workFile.baseStream_.Position = update.CrcPatchOffset;
 2594              workFile.WriteLEInt((int)update.OutEntry.Crc);
 2595            }
 2596
 2597            if (update.SizePatchOffset > 0) {
 2598              workFile.baseStream_.Position = update.SizePatchOffset;
 2599              if (update.OutEntry.LocalHeaderRequiresZip64) {
 2600                workFile.WriteLeLong(update.OutEntry.Size);
 2601                workFile.WriteLeLong(update.OutEntry.CompressedSize);
 2602              } else {
 2603                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);
 2604                workFile.WriteLEInt((int)update.OutEntry.Size);
 2605              }
 2606            }
 2607          }
 2608        }
 2609      } catch {
 2610        workFile.Close();
 2611        if (!directUpdate && (workFile.Name != null)) {
 2612          File.Delete(workFile.Name);
 2613        }
 2614        throw;
 2615      }
 2616
 2617      if (directUpdate) {
 2618        workFile.baseStream_.SetLength(endOfStream);
 2619        workFile.baseStream_.Flush();
 2620        isNewArchive_ = false;
 2621        ReadEntries();
 2622      } else {
 2623        baseStream_.Close();
 2624        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2625      }
 2626    }
 2627
 2628    void CheckUpdating()
 2629    {
 2630      if (updates_ == null) {
 2631        throw new InvalidOperationException("BeginUpdate has not been called");
 2632      }
 2633    }
 2634
 2635    #endregion
 2636
 2637    #region ZipUpdate class
 2638    /// <summary>
 2639    /// Represents a pending update to a Zip file.
 2640    /// </summary>
 2641    class ZipUpdate
 2642    {
 2643      #region Constructors
 2644      public ZipUpdate(string fileName, ZipEntry entry)
 2645      {
 2646        command_ = UpdateCommand.Add;
 2647        entry_ = entry;
 2648        filename_ = fileName;
 2649      }
 2650
 2651      [Obsolete]
 2652      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 2653      {
 2654        command_ = UpdateCommand.Add;
 2655        entry_ = new ZipEntry(entryName);
 2656        entry_.CompressionMethod = compressionMethod;
 2657        filename_ = fileName;
 2658      }
 2659
 2660      [Obsolete]
 2661      public ZipUpdate(string fileName, string entryName)
 2662        : this(fileName, entryName, CompressionMethod.Deflated)
 2663      {
 2664        // Do nothing.
 2665      }
 2666
 2667      [Obsolete]
 2668      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 2669      {
 2670        command_ = UpdateCommand.Add;
 2671        entry_ = new ZipEntry(entryName);
 2672        entry_.CompressionMethod = compressionMethod;
 2673        dataSource_ = dataSource;
 2674      }
 2675
 2676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 2677      {
 2678        command_ = UpdateCommand.Add;
 2679        entry_ = entry;
 2680        dataSource_ = dataSource;
 2681      }
 2682
 2683      public ZipUpdate(ZipEntry original, ZipEntry updated)
 2684      {
 2685        throw new ZipException("Modify not currently supported");
 2686        /*
 2687          command_ = UpdateCommand.Modify;
 2688          entry_ = ( ZipEntry )original.Clone();
 2689          outEntry_ = ( ZipEntry )updated.Clone();
 2690        */
 2691      }
 2692
 2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)
 2694      {
 2695        command_ = command;
 2696        entry_ = (ZipEntry)entry.Clone();
 2697      }
 2698
 2699
 2700      /// <summary>
 2701      /// Copy an existing entry.
 2702      /// </summary>
 2703      /// <param name="entry">The existing entry to copy.</param>
 2704      public ZipUpdate(ZipEntry entry)
 2705        : this(UpdateCommand.Copy, entry)
 2706      {
 2707        // Do nothing.
 2708      }
 2709      #endregion
 2710
 2711      /// <summary>
 2712      /// Get the <see cref="ZipEntry"/> for this update.
 2713      /// </summary>
 2714      /// <remarks>This is the source or original entry.</remarks>
 2715      public ZipEntry Entry {
 2716        get { return entry_; }
 2717      }
 2718
 2719      /// <summary>
 2720      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.
 2721      /// </summary>
 2722      public ZipEntry OutEntry {
 2723        get {
 2724          if (outEntry_ == null) {
 2725            outEntry_ = (ZipEntry)entry_.Clone();
 2726          }
 2727
 2728          return outEntry_;
 2729        }
 2730      }
 2731
 2732      /// <summary>
 2733      /// Get the command for this update.
 2734      /// </summary>
 2735      public UpdateCommand Command {
 2736        get { return command_; }
 2737      }
 2738
 2739      /// <summary>
 2740      /// Get the filename if any for this update.  Null if none exists.
 2741      /// </summary>
 2742      public string Filename {
 2743        get { return filename_; }
 2744      }
 2745
 2746      /// <summary>
 2747      /// Get/set the location of the size patch for this update.
 2748      /// </summary>
 2749      public long SizePatchOffset {
 2750        get { return sizePatchOffset_; }
 2751        set { sizePatchOffset_ = value; }
 2752      }
 2753
 2754      /// <summary>
 2755      /// Get /set the location of the crc patch for this update.
 2756      /// </summary>
 2757      public long CrcPatchOffset {
 2758        get { return crcPatchOffset_; }
 2759        set { crcPatchOffset_ = value; }
 2760      }
 2761
 2762      /// <summary>
 2763      /// Get/set the size calculated by offset.
 2764      /// Specifically, the difference between this and next entry's starting offset.
 2765      /// </summary>
 2766      public long OffsetBasedSize {
 2767        get { return _offsetBasedSize; }
 2768        set { _offsetBasedSize = value; }
 2769      }
 2770
 2771      public Stream GetSource()
 2772      {
 2773        Stream result = null;
 2774        if (dataSource_ != null) {
 2775          result = dataSource_.GetSource();
 2776        }
 2777
 2778        return result;
 2779      }
 2780
 2781      #region Instance Fields
 2782      ZipEntry entry_;
 2783      ZipEntry outEntry_;
 2784      UpdateCommand command_;
 2785      IStaticDataSource dataSource_;
 2786      string filename_;
 2787      long sizePatchOffset_ = -1;
 2788      long crcPatchOffset_ = -1;
 2789      long _offsetBasedSize = -1;
 2790      #endregion
 2791    }
 2792
 2793    #endregion
 2794    #endregion
 2795
 2796    #region Disposing
 2797
 2798    #region IDisposable Members
 2799    void IDisposable.Dispose()
 2800    {
 2801      Close();
 2802    }
 2803    #endregion
 2804
 2805    void DisposeInternal(bool disposing)
 2806    {
 2807      if (!isDisposed_) {
 2808        isDisposed_ = true;
 2809        entries_ = new ZipEntry[0];
 2810
 2811        if (IsStreamOwner && (baseStream_ != null)) {
 2812          lock (baseStream_) {
 2813            baseStream_.Close();
 2814          }
 2815        }
 2816
 2817        PostUpdateCleanup();
 2818      }
 2819    }
 2820
 2821    /// <summary>
 2822    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.
 2823    /// </summary>
 2824    /// <param name="disposing">true to release both managed and unmanaged resources;
 2825    /// false to release only unmanaged resources.</param>
 2826    protected virtual void Dispose(bool disposing)
 2827    {
 2828      DisposeInternal(disposing);
 2829    }
 2830
 2831    #endregion
 2832
 2833    #region Internal routines
 2834    #region Reading
 2835    /// <summary>
 2836    /// Read an unsigned short in little endian byte order.
 2837    /// </summary>
 2838    /// <returns>Returns the value read.</returns>
 2839    /// <exception cref="EndOfStreamException">
 2840    /// The stream ends prematurely
 2841    /// </exception>
 2842    ushort ReadLEUshort()
 2843    {
 2844      int data1 = baseStream_.ReadByte();
 2845
 2846      if (data1 < 0) {
 2847        throw new EndOfStreamException("End of stream");
 2848      }
 2849
 2850      int data2 = baseStream_.ReadByte();
 2851
 2852      if (data2 < 0) {
 2853        throw new EndOfStreamException("End of stream");
 2854      }
 2855
 2856
 2857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));
 2858    }
 2859
 2860    /// <summary>
 2861    /// Read a uint in little endian byte order.
 2862    /// </summary>
 2863    /// <returns>Returns the value read.</returns>
 2864    /// <exception cref="IOException">
 2865    /// An i/o error occurs.
 2866    /// </exception>
 2867    /// <exception cref="System.IO.EndOfStreamException">
 2868    /// The file ends prematurely
 2869    /// </exception>
 2870    uint ReadLEUint()
 2871    {
 2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));
 2873    }
 2874
 2875    ulong ReadLEUlong()
 2876    {
 2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);
 2878    }
 2879
 2880    #endregion
 2881    // NOTE this returns the offset of the first byte after the signature.
 2882    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 2883    {
 2884      using (ZipHelperStream les = new ZipHelperStream(baseStream_)) {
 2885        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
 2886      }
 2887    }
 2888
 2889    /// <summary>
 2890    /// Search for and read the central directory of a zip file filling the entries array.
 2891    /// </summary>
 2892    /// <exception cref="System.IO.IOException">
 2893    /// An i/o error occurs.
 2894    /// </exception>
 2895    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 2896    /// The central directory is malformed or cannot be found
 2897    /// </exception>
 2898    void ReadEntries()
 2899    {
 2900      // Search for the End Of Central Directory.  When a zip comment is
 2901      // present the directory will start earlier
 2902      //
 2903      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
 2904      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
 2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
 2906      // this could be invalid.
 2907      // Could also speed this up by reading memory in larger blocks.
 2908
 2909      if (baseStream_.CanSeek == false) {
 2910        throw new ZipException("ZipFile stream must be seekable");
 2911      }
 2912
 2913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2915
 2916      if (locatedEndOfCentralDir < 0) {
 2917        throw new ZipException("Cannot find central directory");
 2918      }
 2919
 2920      // Read end of central directory record
 2921      ushort thisDiskNumber = ReadLEUshort();
 2922      ushort startCentralDirDisk = ReadLEUshort();
 2923      ulong entriesForThisDisk = ReadLEUshort();
 2924      ulong entriesForWholeCentralDir = ReadLEUshort();
 2925      ulong centralDirSize = ReadLEUint();
 2926      long offsetOfCentralDir = ReadLEUint();
 2927      uint commentSize = ReadLEUshort();
 2928
 2929      if (commentSize > 0) {
 2930        byte[] comment = new byte[commentSize];
 2931
 2932        StreamUtils.ReadFully(baseStream_, comment);
 2933        comment_ = ZipConstants.ConvertToString(comment);
 2934      } else {
 2935        comment_ = string.Empty;
 2936      }
 2937
 2938      bool isZip64 = false;
 2939
 2940      // Check if zip64 header information is required.
 2941      if ((thisDiskNumber == 0xffff) ||
 2942        (startCentralDirDisk == 0xffff) ||
 2943        (entriesForThisDisk == 0xffff) ||
 2944        (entriesForWholeCentralDir == 0xffff) ||
 2945        (centralDirSize == 0xffffffff) ||
 2946        (offsetOfCentralDir == 0xffffffff)) {
 2947        isZip64 = true;
 2948
 2949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 
 2950        if (offset < 0) {
 2951          throw new ZipException("Cannot find Zip64 locator");
 2952        }
 2953
 2954        // number of the disk with the start of the zip64 end of central directory 4 bytes
 2955        // relative offset of the zip64 end of central directory record 8 bytes
 2956        // total number of disks 4 bytes
 2957        ReadLEUint(); // startDisk64 is not currently used
 2958        ulong offset64 = ReadLEUlong();
 2959        uint totalDisks = ReadLEUint();
 2960
 2961        baseStream_.Position = (long)offset64;
 2962        long sig64 = ReadLEUint();
 2963
 2964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {
 2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
 2966        }
 2967
 2968        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
 2969        ulong recordSize = ReadLEUlong();
 2970        int versionMadeBy = ReadLEUshort();
 2971        int versionToExtract = ReadLEUshort();
 2972        uint thisDisk = ReadLEUint();
 2973        uint centralDirDisk = ReadLEUint();
 2974        entriesForThisDisk = ReadLEUlong();
 2975        entriesForWholeCentralDir = ReadLEUlong();
 2976        centralDirSize = ReadLEUlong();
 2977        offsetOfCentralDir = (long)ReadLEUlong();
 2978
 2979        // NOTE: zip64 extensible data sector (variable size) is ignored.
 2980      }
 2981
 2982      entries_ = new ZipEntry[entriesForThisDisk];
 2983
 2984      // SFX/embedded support, find the offset of the first entry vis the start of the stream
 2985      // This applies to Zip files that are appended to the end of an SFX stub.
 2986      // Or are appended as a resource to an executable.
 2987      // Zip files created by some archivers have the offsets altered to reflect the true offsets
 2988      // and so dont require any adjustment here...
 2989      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
 2990      if (!isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize))) {
 2991        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
 2992        if (offsetOfFirstEntry <= 0) {
 2993          throw new ZipException("Invalid embedded zip archive");
 2994        }
 2995      }
 2996
 2997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
 2998
 2999      for (ulong i = 0; i < entriesForThisDisk; i++) {
 3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
 3001          throw new ZipException("Wrong Central Directory signature");
 3002        }
 3003
 3004        int versionMadeBy = ReadLEUshort();
 3005        int versionToExtract = ReadLEUshort();
 3006        int bitFlags = ReadLEUshort();
 3007        int method = ReadLEUshort();
 3008        uint dostime = ReadLEUint();
 3009        uint crc = ReadLEUint();
 3010        var csize = (long)ReadLEUint();
 3011        var size = (long)ReadLEUint();
 3012        int nameLen = ReadLEUshort();
 3013        int extraLen = ReadLEUshort();
 3014        int commentLen = ReadLEUshort();
 3015
 3016        int diskStartNo = ReadLEUshort();  // Not currently used
 3017        int internalAttributes = ReadLEUshort();  // Not currently used
 3018
 3019        uint externalAttributes = ReadLEUint();
 3020        long offset = ReadLEUint();
 3021
 3022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
 3023
 3024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
 3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);
 3026
 3027        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
 3028        entry.Crc = crc & 0xffffffffL;
 3029        entry.Size = size & 0xffffffffL;
 3030        entry.CompressedSize = csize & 0xffffffffL;
 3031        entry.Flags = bitFlags;
 3032        entry.DosTime = (uint)dostime;
 3033        entry.ZipFileIndex = (long)i;
 3034        entry.Offset = offset;
 3035        entry.ExternalFileAttributes = (int)externalAttributes;
 3036
 3037        if ((bitFlags & 8) == 0) {
 3038          entry.CryptoCheckValue = (byte)(crc >> 24);
 3039        } else {
 3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
 3041        }
 3042
 3043        if (extraLen > 0) {
 3044          byte[] extra = new byte[extraLen];
 3045          StreamUtils.ReadFully(baseStream_, extra);
 3046          entry.ExtraData = extra;
 3047        }
 3048
 3049        entry.ProcessExtraData(false);
 3050
 3051        if (commentLen > 0) {
 3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
 3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
 3054        }
 3055
 3056        entries_[i] = entry;
 3057      }
 3058    }
 3059
 3060    /// <summary>
 3061    /// Locate the data for a given entry.
 3062    /// </summary>
 3063    /// <returns>
 3064    /// The start offset of the data.
 3065    /// </returns>
 3066    /// <exception cref="System.IO.EndOfStreamException">
 3067    /// The stream ends prematurely
 3068    /// </exception>
 3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 3070    /// The local header signature is invalid, the entry and central header file name lengths are different
 3071    /// or the local and entry compression methods dont match
 3072    /// </exception>
 3073    long LocateEntry(ZipEntry entry)
 3074    {
 3075      return TestLocalHeader(entry, HeaderTest.Extract);
 3076    }
 3077
 3078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
 3079    {
 3080      CryptoStream result = null;
 3081
 3082      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3084        var classicManaged = new PkzipClassicManaged();
 3085
 3086        OnKeysRequired(entry.Name);
 3087        if (HaveKeys == false) {
 3088          throw new ZipException("No password available for encrypted stream");
 3089        }
 3090
 3091        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
 3092        CheckClassicPassword(result, entry);
 3093      } else {
 3094        if (entry.Version == ZipConstants.VERSION_AES) {
 3095          //
 3096          OnKeysRequired(entry.Name);
 3097          if (HaveKeys == false) {
 3098            throw new ZipException("No password available for AES encrypted stream");
 3099          }
 3100          int saltLen = entry.AESSaltLen;
 3101          byte[] saltBytes = new byte[saltLen];
 3102          int saltIn = baseStream.Read(saltBytes, 0, saltLen);
 3103          if (saltIn != saltLen)
 3104            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
 3105          //
 3106          byte[] pwdVerifyRead = new byte[2];
 3107          baseStream.Read(pwdVerifyRead, 0, 2);
 3108          int blockSize = entry.AESKeySize / 8;   // bits to bytes
 3109
 3110          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
 3111          byte[] pwdVerifyCalc = decryptor.PwdVerifier;
 3112          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
 3113            throw new ZipException("Invalid password for AES");
 3114          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
 3115        } else {
 3116          throw new ZipException("Decryption method not supported");
 3117        }
 3118      }
 3119
 3120      return result;
 3121    }
 3122
 3123    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
 3124    {
 3125      CryptoStream result = null;
 3126      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3127        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3128        var classicManaged = new PkzipClassicManaged();
 3129
 3130        OnKeysRequired(entry.Name);
 3131        if (HaveKeys == false) {
 3132          throw new ZipException("No password available for encrypted stream");
 3133        }
 3134
 3135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
 3136        // which doesnt do this.
 3137        result = new CryptoStream(new UncompressedStream(baseStream),
 3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
 3139
 3140        if ((entry.Crc < 0) || (entry.Flags & 8) != 0) {
 3141          WriteEncryptionHeader(result, entry.DosTime << 16);
 3142        } else {
 3143          WriteEncryptionHeader(result, entry.Crc);
 3144        }
 3145      }
 3146      return result;
 3147    }
 3148
 3149    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
 3150    {
 3151      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
 3152      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
 3153      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
 3154        throw new ZipException("Invalid password");
 3155      }
 3156    }
 3157
 3158    static void WriteEncryptionHeader(Stream stream, long crcValue)
 3159    {
 3160      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
 3161      var rnd = new Random();
 3162      rnd.NextBytes(cryptBuffer);
 3163      cryptBuffer[11] = (byte)(crcValue >> 24);
 3164      stream.Write(cryptBuffer, 0, cryptBuffer.Length);
 3165    }
 3166
 3167    #endregion
 3168
 3169    #region Instance Fields
 3170    bool isDisposed_;
 3171    string name_;
 3172    string comment_;
 3173    string rawPassword_;
 3174    Stream baseStream_;
 3175    bool isStreamOwner;
 3176    long offsetOfFirstEntry;
 3177    ZipEntry[] entries_;
 3178    byte[] key;
 3179    bool isNewArchive_;
 3180
 3181    // Default is dynamic which is not backwards compatible and can cause problems
 3182    // with XP's built in compression which cant read Zip64 archives.
 3183    // However it does avoid the situation were a large file is added and cannot be completed correctly.
 3184    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.
 3185    UseZip64 useZip64_ = UseZip64.Dynamic;
 3186
 3187    #region Zip Update Instance Fields
 3188    ArrayList updates_;
 3189    long updateCount_; // Count is managed manually as updates_ can contain nulls!
 3190    Hashtable updateIndex_;
 3191    IArchiveStorage archiveStorage_;
 3192    IDynamicDataSource updateDataSource_;
 3193    bool contentsEdited_;
 3194    int bufferSize_ = DefaultBufferSize;
 3195    byte[] copyBuffer_;
 3196    ZipString newComment_;
 3197    bool commentEdited_;
 3198    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();
 3199    #endregion
 3200    #endregion
 3201
 3202    #region Support Classes
 3203    /// <summary>
 3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.
 3205    /// </summary>
 3206    class ZipString
 3207    {
 3208      #region Constructors
 3209      /// <summary>
 3210      /// Initialise a <see cref="ZipString"/> with a string.
 3211      /// </summary>
 3212      /// <param name="comment">The textual string form.</param>
 3213      public ZipString(string comment)
 3214      {
 3215        comment_ = comment;
 3216        isSourceString_ = true;
 3217      }
 3218
 3219      /// <summary>
 3220      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.
 3221      /// </summary>
 3222      /// <param name="rawString"></param>
 3223      public ZipString(byte[] rawString)
 3224      {
 3225        rawComment_ = rawString;
 3226      }
 3227      #endregion
 3228
 3229      /// <summary>
 3230      /// Get a value indicating the original source of data for this instance.
 3231      /// True if the source was a string; false if the source was binary data.
 3232      /// </summary>
 3233      public bool IsSourceString {
 3234        get { return isSourceString_; }
 3235      }
 3236
 3237      /// <summary>
 3238      /// Get the length of the comment when represented as raw bytes.
 3239      /// </summary>
 3240      public int RawLength {
 3241        get {
 3242          MakeBytesAvailable();
 3243          return rawComment_.Length;
 3244        }
 3245      }
 3246
 3247      /// <summary>
 3248      /// Get the comment in its 'raw' form as plain bytes.
 3249      /// </summary>
 3250      public byte[] RawComment {
 3251        get {
 3252          MakeBytesAvailable();
 3253          return (byte[])rawComment_.Clone();
 3254        }
 3255      }
 3256
 3257      /// <summary>
 3258      /// Reset the comment to its initial state.
 3259      /// </summary>
 3260      public void Reset()
 3261      {
 3262        if (isSourceString_) {
 3263          rawComment_ = null;
 3264        } else {
 3265          comment_ = null;
 3266        }
 3267      }
 3268
 3269      void MakeTextAvailable()
 3270      {
 3271        if (comment_ == null) {
 3272          comment_ = ZipConstants.ConvertToString(rawComment_);
 3273        }
 3274      }
 3275
 3276      void MakeBytesAvailable()
 3277      {
 3278        if (rawComment_ == null) {
 3279          rawComment_ = ZipConstants.ConvertToArray(comment_);
 3280        }
 3281      }
 3282
 3283      /// <summary>
 3284      /// Implicit conversion of comment to a string.
 3285      /// </summary>
 3286      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>
 3287      /// <returns>The textual equivalent for the input value.</returns>
 3288      static public implicit operator string(ZipString zipString)
 3289      {
 3290        zipString.MakeTextAvailable();
 3291        return zipString.comment_;
 3292      }
 3293
 3294      #region Instance Fields
 3295      string comment_;
 3296      byte[] rawComment_;
 3297      bool isSourceString_;
 3298      #endregion
 3299    }
 3300
 3301    /// <summary>
 3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>
 3303    /// </summary>
 3304    class ZipEntryEnumerator : IEnumerator
 3305    {
 3306      #region Constructors
 3307      public ZipEntryEnumerator(ZipEntry[] entries)
 3308      {
 3309        array = entries;
 3310      }
 3311
 3312      #endregion
 3313      #region IEnumerator Members
 3314      public object Current {
 3315        get {
 3316          return array[index];
 3317        }
 3318      }
 3319
 3320      public void Reset()
 3321      {
 3322        index = -1;
 3323      }
 3324
 3325      public bool MoveNext()
 3326      {
 3327        return (++index < array.Length);
 3328      }
 3329      #endregion
 3330      #region Instance Fields
 3331      ZipEntry[] array;
 3332      int index = -1;
 3333      #endregion
 3334    }
 3335
 3336    /// <summary>
 3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data
 3338    /// to and flush, but cannot read, seek or do anything else to.
 3339    /// </summary>
 3340    class UncompressedStream : Stream
 3341    {
 3342      #region Constructors
 3343      public UncompressedStream(Stream baseStream)
 3344      {
 3345        baseStream_ = baseStream;
 3346      }
 3347
 3348      #endregion
 3349
 3350      /// <summary>
 3351      /// Close this stream instance.
 3352      /// </summary>
 3353      public override void Close()
 3354      {
 3355        // Do nothing
 3356      }
 3357
 3358      /// <summary>
 3359      /// Gets a value indicating whether the current stream supports reading.
 3360      /// </summary>
 3361      public override bool CanRead {
 3362        get {
 3363          return false;
 3364        }
 3365      }
 3366
 3367      /// <summary>
 3368      /// Write any buffered data to underlying storage.
 3369      /// </summary>
 3370      public override void Flush()
 3371      {
 3372        baseStream_.Flush();
 3373      }
 3374
 3375      /// <summary>
 3376      /// Gets a value indicating whether the current stream supports writing.
 3377      /// </summary>
 3378      public override bool CanWrite {
 3379        get {
 3380          return baseStream_.CanWrite;
 3381        }
 3382      }
 3383
 3384      /// <summary>
 3385      /// Gets a value indicating whether the current stream supports seeking.
 3386      /// </summary>
 3387      public override bool CanSeek {
 3388        get {
 3389          return false;
 3390        }
 3391      }
 3392
 3393      /// <summary>
 3394      /// Get the length in bytes of the stream.
 3395      /// </summary>
 3396      public override long Length {
 3397        get {
 3398          return 0;
 3399        }
 3400      }
 3401
 3402      /// <summary>
 3403      /// Gets or sets the position within the current stream.
 3404      /// </summary>
 3405      public override long Position {
 3406        get {
 3407          return baseStream_.Position;
 3408        }
 3409        set {
 3410          throw new NotImplementedException();
 3411        }
 3412      }
 3413
 3414      /// <summary>
 3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3416      /// </summary>
 3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3419      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3420      /// <returns>
 3421      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3422      /// </returns>
 3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3425      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3426      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3427      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3428      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3429      public override int Read(byte[] buffer, int offset, int count)
 3430      {
 3431        return 0;
 3432      }
 3433
 3434      /// <summary>
 3435      /// Sets the position within the current stream.
 3436      /// </summary>
 3437      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3438      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3439      /// <returns>
 3440      /// The new position within the current stream.
 3441      /// </returns>
 3442      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3443      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3445      public override long Seek(long offset, SeekOrigin origin)
 3446      {
 3447        return 0;
 3448      }
 3449
 3450      /// <summary>
 3451      /// Sets the length of the current stream.
 3452      /// </summary>
 3453      /// <param name="value">The desired length of the current stream in bytes.</param>
 3454      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3455      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3456      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3457      public override void SetLength(long value)
 3458      {
 3459      }
 3460
 3461      /// <summary>
 3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3463      /// </summary>
 3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3466      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3467      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3468      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3469      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3470      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3471      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3472      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3473      public override void Write(byte[] buffer, int offset, int count)
 3474      {
 3475        baseStream_.Write(buffer, offset, count);
 3476      }
 3477
 3478      readonly
 3479
 3480      #region Instance Fields
 3481      Stream baseStream_;
 3482      #endregion
 3483    }
 3484
 3485    /// <summary>
 3486    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>
 3487    /// whose data is only a part or subsection of a file.
 3488    /// </summary>
 3489    class PartialInputStream : Stream
 3490    {
 3491      #region Constructors
 3492      /// <summary>
 3493      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.
 3494      /// </summary>
 3495      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>
 3496      /// <param name="start">The start of the partial data.</param>
 3497      /// <param name="length">The length of the partial data.</param>
 3498      public PartialInputStream(ZipFile zipFile, long start, long length)
 3499      {
 3500        start_ = start;
 3501        length_ = length;
 3502
 3503        // Although this is the only time the zipfile is used
 3504        // keeping a reference here prevents premature closure of
 3505        // this zip file and thus the baseStream_.
 3506
 3507        // Code like this will cause apparently random failures depending
 3508        // on the size of the files and when garbage is collected.
 3509        //
 3510        // ZipFile z = new ZipFile (stream);
 3511        // Stream reader = z.GetInputStream(0);
 3512        // uses reader here....
 3513        zipFile_ = zipFile;
 3514        baseStream_ = zipFile_.baseStream_;
 3515        readPos_ = start;
 3516        end_ = start + length;
 3517      }
 3518      #endregion
 3519
 3520      /// <summary>
 3521      /// Read a byte from this stream.
 3522      /// </summary>
 3523      /// <returns>Returns the byte read or -1 on end of stream.</returns>
 3524      public override int ReadByte()
 3525      {
 3526        if (readPos_ >= end_) {
 3527          // -1 is the correct value at end of stream.
 3528          return -1;
 3529        }
 3530
 3531        lock (baseStream_) {
 3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);
 3533          return baseStream_.ReadByte();
 3534        }
 3535      }
 3536
 3537      /// <summary>
 3538      /// Close this <see cref="PartialInputStream">partial input stream</see>.
 3539      /// </summary>
 3540      /// <remarks>
 3541      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.
 3542      /// </remarks>
 3543      public override void Close()
 3544      {
 3545        // Do nothing at all!
 3546      }
 3547
 3548      /// <summary>
 3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3550      /// </summary>
 3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3553      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3554      /// <returns>
 3555      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3556      /// </returns>
 3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3559      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3560      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3561      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3562      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3563      public override int Read(byte[] buffer, int offset, int count)
 3564      {
 3565        lock (baseStream_) {
 3566          if (count > end_ - readPos_) {
 3567            count = (int)(end_ - readPos_);
 3568            if (count == 0) {
 3569              return 0;
 3570            }
 3571          }
 3572          // Protect against Stream implementations that throw away their buffer on every Seek
 3573          // (for example, Mono FileStream)
 3574          if (baseStream_.Position != readPos_) {
 3575            baseStream_.Seek(readPos_, SeekOrigin.Begin);
 3576          }
 3577          int readCount = baseStream_.Read(buffer, offset, count);
 3578          if (readCount > 0) {
 3579            readPos_ += readCount;
 3580          }
 3581          return readCount;
 3582        }
 3583      }
 3584
 3585      /// <summary>
 3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3587      /// </summary>
 3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3590      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3591      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3592      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3593      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3594      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3595      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3596      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3597      public override void Write(byte[] buffer, int offset, int count)
 3598      {
 3599        throw new NotSupportedException();
 3600      }
 3601
 3602      /// <summary>
 3603      /// When overridden in a derived class, sets the length of the current stream.
 3604      /// </summary>
 3605      /// <param name="value">The desired length of the current stream in bytes.</param>
 3606      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3607      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3608      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3609      public override void SetLength(long value)
 3610      {
 3611        throw new NotSupportedException();
 3612      }
 3613
 3614      /// <summary>
 3615      /// When overridden in a derived class, sets the position within the current stream.
 3616      /// </summary>
 3617      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3618      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3619      /// <returns>
 3620      /// The new position within the current stream.
 3621      /// </returns>
 3622      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3623      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3625      public override long Seek(long offset, SeekOrigin origin)
 3626      {
 3627        long newPos = readPos_;
 3628
 3629        switch (origin) {
 3630          case SeekOrigin.Begin:
 3631            newPos = start_ + offset;
 3632            break;
 3633
 3634          case SeekOrigin.Current:
 3635            newPos = readPos_ + offset;
 3636            break;
 3637
 3638          case SeekOrigin.End:
 3639            newPos = end_ + offset;
 3640            break;
 3641        }
 3642
 3643        if (newPos < start_) {
 3644          throw new ArgumentException("Negative position is invalid");
 3645        }
 3646
 3647        if (newPos >= end_) {
 3648          throw new IOException("Cannot seek past end");
 3649        }
 3650        readPos_ = newPos;
 3651        return readPos_;
 3652      }
 3653
 3654      /// <summary>
 3655      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
 3656      /// </summary>
 3657      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3658      public override void Flush()
 3659      {
 3660        // Nothing to do.
 3661      }
 3662
 3663      /// <summary>
 3664      /// Gets or sets the position within the current stream.
 3665      /// </summary>
 3666      /// <value></value>
 3667      /// <returns>The current position within the stream.</returns>
 3668      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3669      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>
 3670      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3671      public override long Position {
 3672        get { return readPos_ - start_; }
 3673        set {
 3674          long newPos = start_ + value;
 3675
 3676          if (newPos < start_) {
 3677            throw new ArgumentException("Negative position is invalid");
 3678          }
 3679
 3680          if (newPos >= end_) {
 3681            throw new InvalidOperationException("Cannot seek past end");
 3682          }
 3683          readPos_ = newPos;
 3684        }
 3685      }
 3686
 3687      /// <summary>
 3688      /// Gets the length in bytes of the stream.
 3689      /// </summary>
 3690      /// <value></value>
 3691      /// <returns>A long value representing the length of the stream in bytes.</returns>
 3692      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep
 3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3694      public override long Length {
 3695        get { return length_; }
 3696      }
 3697
 3698      /// <summary>
 3699      /// Gets a value indicating whether the current stream supports writing.
 3700      /// </summary>
 3701      /// <value>false</value>
 3702      /// <returns>true if the stream supports writing; otherwise, false.</returns>
 3703      public override bool CanWrite {
 3704        get { return false; }
 3705      }
 3706
 3707      /// <summary>
 3708      /// Gets a value indicating whether the current stream supports seeking.
 3709      /// </summary>
 3710      /// <value>true</value>
 3711      /// <returns>true if the stream supports seeking; otherwise, false.</returns>
 3712      public override bool CanSeek {
 3713        get { return true; }
 3714      }
 3715
 3716      /// <summary>
 3717      /// Gets a value indicating whether the current stream supports reading.
 3718      /// </summary>
 3719      /// <value>true.</value>
 3720      /// <returns>true if the stream supports reading; otherwise, false.</returns>
 3721      public override bool CanRead {
 3722        get { return true; }
 3723      }
 3724
 3725      /// <summary>
 3726      /// Gets a value that determines whether the current stream can time out.
 3727      /// </summary>
 3728      /// <value></value>
 3729      /// <returns>A value that determines whether the current stream can time out.</returns>
 3730      public override bool CanTimeout {
 3731        get { return baseStream_.CanTimeout; }
 3732      }
 3733      #region Instance Fields
 3734      ZipFile zipFile_;
 3735      Stream baseStream_;
 3736      long start_;
 3737      long length_;
 3738      long readPos_;
 3739      long end_;
 3740      #endregion
 3741    }
 3742    #endregion
 3743  }
 3744
 3745  #endregion
 3746
 3747  #region DataSources
 3748  /// <summary>
 3749  /// Provides a static way to obtain a source of data for an entry.
 3750  /// </summary>
 3751  public interface IStaticDataSource
 3752  {
 3753    /// <summary>
 3754    /// Get a source of data by creating a new stream.
 3755    /// </summary>
 3756    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3757    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3758    Stream GetSource();
 3759  }
 3760
 3761  /// <summary>
 3762  /// Represents a source of data that can dynamically provide
 3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.
 3764  /// </summary>
 3765  public interface IDynamicDataSource
 3766  {
 3767    /// <summary>
 3768    /// Get a data source.
 3769    /// </summary>
 3770    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>
 3771    /// <param name="name">The name for data if known.</param>
 3772    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3773    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3774    Stream GetSource(ZipEntry entry, string name);
 3775  }
 3776
 3777  /// <summary>
 3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.
 3779  /// </summary>
 3780  public class StaticDiskDataSource : IStaticDataSource
 3781  {
 3782    /// <summary>
 3783    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>
 3784    /// </summary>
 3785    /// <param name="fileName">The name of the file to obtain data from.</param>
 3786    public StaticDiskDataSource(string fileName)
 3787    {
 3788      fileName_ = fileName;
 3789    }
 3790
 3791    #region IDataSource Members
 3792
 3793    /// <summary>
 3794    /// Get a <see cref="Stream"/> providing data.
 3795    /// </summary>
 3796    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>
 3797    public Stream GetSource()
 3798    {
 3799      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 3800    }
 3801
 3802    readonly
 3803
 3804    #endregion
 3805    #region Instance Fields
 3806    string fileName_;
 3807    #endregion
 3808  }
 3809
 3810
 3811  /// <summary>
 3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.
 3813  /// </summary>
 3814  public class DynamicDiskDataSource : IDynamicDataSource
 3815  {
 3816
 3817    #region IDataSource Members
 3818    /// <summary>
 3819    /// Get a <see cref="Stream"/> providing data for an entry.
 3820    /// </summary>
 3821    /// <param name="entry">The entry to provide data for.</param>
 3822    /// <param name="name">The file name for data if known.</param>
 3823    /// <returns>Returns a stream providing data; or null if not available</returns>
 3824    public Stream GetSource(ZipEntry entry, string name)
 3825    {
 3826      Stream result = null;
 3827
 3828      if (name != null) {
 3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 3830      }
 3831
 3832      return result;
 3833    }
 3834
 3835    #endregion
 3836  }
 3837
 3838  #endregion
 3839
 3840  #region Archive Storage
 3841  /// <summary>
 3842  /// Defines facilities for data storage when updating Zip Archives.
 3843  /// </summary>
 3844  public interface IArchiveStorage
 3845  {
 3846    /// <summary>
 3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.
 3848    /// </summary>
 3849    FileUpdateMode UpdateMode { get; }
 3850
 3851    /// <summary>
 3852    /// Get an empty <see cref="Stream"/> that can be used for temporary output.
 3853    /// </summary>
 3854    /// <returns>Returns a temporary output <see cref="Stream"/></returns>
 3855    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3856    Stream GetTemporaryOutput();
 3857
 3858    /// <summary>
 3859    /// Convert a temporary output stream to a final stream.
 3860    /// </summary>
 3861    /// <returns>The resulting final <see cref="Stream"/></returns>
 3862    /// <seealso cref="GetTemporaryOutput"/>
 3863    Stream ConvertTemporaryToFinal();
 3864
 3865    /// <summary>
 3866    /// Make a temporary copy of the original stream.
 3867    /// </summary>
 3868    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 3869    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3870    Stream MakeTemporaryCopy(Stream stream);
 3871
 3872    /// <summary>
 3873    /// Return a stream suitable for performing direct updates on the original source.
 3874    /// </summary>
 3875    /// <param name="stream">The current stream.</param>
 3876    /// <returns>Returns a stream suitable for direct updating.</returns>
 3877    /// <remarks>This may be the current stream passed.</remarks>
 3878    Stream OpenForDirectUpdate(Stream stream);
 3879
 3880    /// <summary>
 3881    /// Dispose of this instance.
 3882    /// </summary>
 3883    void Dispose();
 3884  }
 3885
 3886  /// <summary>
 3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.
 3888  /// </summary>
 3889  abstract public class BaseArchiveStorage : IArchiveStorage
 3890  {
 3891    #region Constructors
 3892    /// <summary>
 3893    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.
 3894    /// </summary>
 3895    /// <param name="updateMode">The update mode.</param>
 3896    protected BaseArchiveStorage(FileUpdateMode updateMode)
 3897    {
 3898      updateMode_ = updateMode;
 3899    }
 3900    #endregion
 3901
 3902    #region IArchiveStorage Members
 3903
 3904    /// <summary>
 3905    /// Gets a temporary output <see cref="Stream"/>
 3906    /// </summary>
 3907    /// <returns>Returns the temporary output stream.</returns>
 3908    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3909    public abstract Stream GetTemporaryOutput();
 3910
 3911    /// <summary>
 3912    /// Converts the temporary <see cref="Stream"/> to its final form.
 3913    /// </summary>
 3914    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 3915    /// the final storage for the archive.</returns>
 3916    /// <seealso cref="GetTemporaryOutput"/>
 3917    public abstract Stream ConvertTemporaryToFinal();
 3918
 3919    /// <summary>
 3920    /// Make a temporary copy of a <see cref="Stream"/>.
 3921    /// </summary>
 3922    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>
 3923    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3924    public abstract Stream MakeTemporaryCopy(Stream stream);
 3925
 3926    /// <summary>
 3927    /// Return a stream suitable for performing direct updates on the original source.
 3928    /// </summary>
 3929    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>
 3930    /// <returns>Returns a stream suitable for direct updating.</returns>
 3931    public abstract Stream OpenForDirectUpdate(Stream stream);
 3932
 3933    /// <summary>
 3934    /// Disposes this instance.
 3935    /// </summary>
 3936    public abstract void Dispose();
 3937
 3938    /// <summary>
 3939    /// Gets the update mode applicable.
 3940    /// </summary>
 3941    /// <value>The update mode.</value>
 3942    public FileUpdateMode UpdateMode {
 3943      get {
 3944        return updateMode_;
 3945      }
 3946    }
 3947
 3948    #endregion
 3949
 3950    #region Instance Fields
 3951    FileUpdateMode updateMode_;
 3952    #endregion
 3953  }
 3954
 3955  /// <summary>
 3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.
 3957  /// </summary>
 3958  public class DiskArchiveStorage : BaseArchiveStorage
 3959  {
 3960    #region Constructors
 3961    /// <summary>
 3962    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3963    /// </summary>
 3964    /// <param name="file">The file.</param>
 3965    /// <param name="updateMode">The update mode.</param>
 3966    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)
 3967      : base(updateMode)
 3968    {
 3969      if (file.Name == null) {
 3970        throw new ZipException("Cant handle non file archives");
 3971      }
 3972
 3973      fileName_ = file.Name;
 3974    }
 3975
 3976    /// <summary>
 3977    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3978    /// </summary>
 3979    /// <param name="file">The file.</param>
 3980    public DiskArchiveStorage(ZipFile file)
 3981      : this(file, FileUpdateMode.Safe)
 3982    {
 3983    }
 3984    #endregion
 3985
 3986    #region IArchiveStorage Members
 3987
 3988    /// <summary>
 3989    /// Gets a temporary output <see cref="Stream"/> for performing updates on.
 3990    /// </summary>
 3991    /// <returns>Returns the temporary output stream.</returns>
 3992    public override Stream GetTemporaryOutput()
 3993    {
 3994      if (temporaryName_ != null) {
 3995        temporaryName_ = GetTempFileName(temporaryName_, true);
 3996        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 3997      } else {
 3998        // Determine where to place files based on internal strategy.
 3999        // Currently this is always done in system temp directory.
 4000        temporaryName_ = Path.GetTempFileName();
 4001        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 4002      }
 4003
 4004      return temporaryStream_;
 4005    }
 4006
 4007    /// <summary>
 4008    /// Converts a temporary <see cref="Stream"/> to its final form.
 4009    /// </summary>
 4010    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4011    /// the final storage for the archive.</returns>
 4012    public override Stream ConvertTemporaryToFinal()
 4013    {
 4014      if (temporaryStream_ == null) {
 4015        throw new ZipException("No temporary stream has been created");
 4016      }
 4017
 4018      Stream result = null;
 4019
 4020      string moveTempName = GetTempFileName(fileName_, false);
 4021      bool newFileCreated = false;
 4022
 4023      try {
 4024        temporaryStream_.Close();
 4025        File.Move(fileName_, moveTempName);
 4026        File.Move(temporaryName_, fileName_);
 4027        newFileCreated = true;
 4028        File.Delete(moveTempName);
 4029
 4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 4031      } catch (Exception) {
 4032        result = null;
 4033
 4034        // Try to roll back changes...
 4035        if (!newFileCreated) {
 4036          File.Move(moveTempName, fileName_);
 4037          File.Delete(temporaryName_);
 4038        }
 4039
 4040        throw;
 4041      }
 4042
 4043      return result;
 4044    }
 4045
 4046    /// <summary>
 4047    /// Make a temporary copy of a stream.
 4048    /// </summary>
 4049    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4050    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4051    public override Stream MakeTemporaryCopy(Stream stream)
 4052    {
 4053      stream.Close();
 4054
 4055      temporaryName_ = GetTempFileName(fileName_, true);
 4056      File.Copy(fileName_, temporaryName_, true);
 4057
 4058      temporaryStream_ = new FileStream(temporaryName_,
 4059        FileMode.Open,
 4060        FileAccess.ReadWrite);
 4061      return temporaryStream_;
 4062    }
 4063
 4064    /// <summary>
 4065    /// Return a stream suitable for performing direct updates on the original source.
 4066    /// </summary>
 4067    /// <param name="stream">The current stream.</param>
 4068    /// <returns>Returns a stream suitable for direct updating.</returns>
 4069    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>
 4070    public override Stream OpenForDirectUpdate(Stream stream)
 4071    {
 4072      Stream result;
 4073      if ((stream == null) || !stream.CanWrite) {
 4074        if (stream != null) {
 4075          stream.Close();
 4076        }
 4077
 4078        result = new FileStream(fileName_,
 4079            FileMode.Open,
 4080            FileAccess.ReadWrite);
 4081      } else {
 4082        result = stream;
 4083      }
 4084
 4085      return result;
 4086    }
 4087
 4088    /// <summary>
 4089    /// Disposes this instance.
 4090    /// </summary>
 4091    public override void Dispose()
 4092    {
 4093      if (temporaryStream_ != null) {
 4094        temporaryStream_.Close();
 4095      }
 4096    }
 4097
 4098    #endregion
 4099
 4100    #region Internal routines
 4101    static string GetTempFileName(string original, bool makeTempFile)
 4102    {
 4103      string result = null;
 4104
 4105      if (original == null) {
 4106        result = Path.GetTempFileName();
 4107      } else {
 4108        int counter = 0;
 4109        int suffixSeed = DateTime.Now.Second;
 4110
 4111        while (result == null) {
 4112          counter += 1;
 4113          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);
 4114          if (!File.Exists(newName)) {
 4115            if (makeTempFile) {
 4116              try {
 4117                // Try and create the file.
 4118                using (FileStream stream = File.Create(newName)) {
 4119                }
 4120                result = newName;
 4121              } catch {
 4122                suffixSeed = DateTime.Now.Second;
 4123              }
 4124            } else {
 4125              result = newName;
 4126            }
 4127          }
 4128        }
 4129      }
 4130      return result;
 4131    }
 4132    #endregion
 4133
 4134    #region Instance Fields
 4135    Stream temporaryStream_;
 4136    string fileName_;
 4137    string temporaryName_;
 4138    #endregion
 4139  }
 4140
 4141  /// <summary>
 4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.
 4143  /// </summary>
 4144  public class MemoryArchiveStorage : BaseArchiveStorage
 4145  {
 4146    #region Constructors
 4147    /// <summary>
 4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4149    /// </summary>
 4150    public MemoryArchiveStorage()
 364151      : base(FileUpdateMode.Direct)
 4152    {
 364153    }
 4154
 4155    /// <summary>
 4156    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4157    /// </summary>
 4158    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>
 4159    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>
 4160    public MemoryArchiveStorage(FileUpdateMode updateMode)
 14161      : base(updateMode)
 4162    {
 14163    }
 4164
 4165    #endregion
 4166
 4167    #region Properties
 4168    /// <summary>
 4169    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.
 4170    /// </summary>
 4171    public MemoryStream FinalStream {
 04172      get { return finalStream_; }
 4173    }
 4174
 4175    #endregion
 4176
 4177    #region IArchiveStorage Members
 4178
 4179    /// <summary>
 4180    /// Gets the temporary output <see cref="Stream"/>
 4181    /// </summary>
 4182    /// <returns>Returns the temporary output stream.</returns>
 4183    public override Stream GetTemporaryOutput()
 4184    {
 14185      temporaryStream_ = new MemoryStream();
 14186      return temporaryStream_;
 4187    }
 4188
 4189    /// <summary>
 4190    /// Converts the temporary <see cref="Stream"/> to its final form.
 4191    /// </summary>
 4192    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4193    /// the final storage for the archive.</returns>
 4194    public override Stream ConvertTemporaryToFinal()
 4195    {
 14196       if (temporaryStream_ == null) {
 04197        throw new ZipException("No temporary stream has been created");
 4198      }
 4199
 14200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());
 14201      return finalStream_;
 4202    }
 4203
 4204    /// <summary>
 4205    /// Make a temporary copy of the original stream.
 4206    /// </summary>
 4207    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4208    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4209    public override Stream MakeTemporaryCopy(Stream stream)
 4210    {
 04211      temporaryStream_ = new MemoryStream();
 04212      stream.Position = 0;
 04213      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);
 04214      return temporaryStream_;
 4215    }
 4216
 4217    /// <summary>
 4218    /// Return a stream suitable for performing direct updates on the original source.
 4219    /// </summary>
 4220    /// <param name="stream">The original source stream</param>
 4221    /// <returns>Returns a stream suitable for direct updating.</returns>
 4222    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;
 4223    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>
 4224    public override Stream OpenForDirectUpdate(Stream stream)
 4225    {
 4226      Stream result;
 14227       if ((stream == null) || !stream.CanWrite) {
 4228
 04229        result = new MemoryStream();
 4230
 04231         if (stream != null) {
 04232          stream.Position = 0;
 04233          StreamUtils.Copy(stream, result, new byte[4096]);
 4234
 04235          stream.Close();
 4236        }
 04237      } else {
 14238        result = stream;
 4239      }
 4240
 14241      return result;
 4242    }
 4243
 4244    /// <summary>
 4245    /// Disposes this instance.
 4246    /// </summary>
 4247    public override void Dispose()
 4248    {
 374249       if (temporaryStream_ != null) {
 14250        temporaryStream_.Close();
 4251      }
 374252    }
 4253
 4254    #endregion
 4255
 4256    #region Instance Fields
 4257    MemoryStream temporaryStream_;
 4258    MemoryStream finalStream_;
 4259    #endregion
 4260  }
 4261
 4262  #endregion
 4263}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_NTTaggedData.htm b/docs/opencover/ICSharpCode.SharpZipLib_NTTaggedData.htm new file mode 100644 index 000000000..4209b7bf3 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_NTTaggedData.htm @@ -0,0 +1,941 @@ + + + + +ICSharpCode.SharpZipLib.Zip.NTTaggedData - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.NTTaggedData
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipExtraData.cs
Covered lines:45
Uncovered lines:9
Coverable lines:54
Total lines:896
Line coverage:83.3%
Branch coverage:50%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
SetData(...)688.8957.14
GetData()3100100
IsValidValue(...)157.14100
.ctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipExtraData.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Zip
 5{
 6  // TODO: Sort out wether tagged data is useful and what a good implementation might look like.
 7  // Its just a sketch of an idea at the moment.
 8
 9  /// <summary>
 10  /// ExtraData tagged value interface.
 11  /// </summary>
 12  public interface ITaggedData
 13  {
 14    /// <summary>
 15    /// Get the ID for this tagged data value.
 16    /// </summary>
 17    short TagID { get; }
 18
 19    /// <summary>
 20    /// Set the contents of this instance from the data passed.
 21    /// </summary>
 22    /// <param name="data">The data to extract contents from.</param>
 23    /// <param name="offset">The offset to begin extracting data from.</param>
 24    /// <param name="count">The number of bytes to extract.</param>
 25    void SetData(byte[] data, int offset, int count);
 26
 27    /// <summary>
 28    /// Get the data representing this instance.
 29    /// </summary>
 30    /// <returns>Returns the data for this instance.</returns>
 31    byte[] GetData();
 32  }
 33
 34  /// <summary>
 35  /// A raw binary tagged value
 36  /// </summary>
 37  public class RawTaggedData : ITaggedData
 38  {
 39    /// <summary>
 40    /// Initialise a new instance.
 41    /// </summary>
 42    /// <param name="tag">The tag ID.</param>
 43    public RawTaggedData(short tag)
 44    {
 45      _tag = tag;
 46    }
 47
 48    #region ITaggedData Members
 49
 50    /// <summary>
 51    /// Get the ID for this tagged data value.
 52    /// </summary>
 53    public short TagID {
 54      get { return _tag; }
 55      set { _tag = value; }
 56    }
 57
 58    /// <summary>
 59    /// Set the data from the raw values provided.
 60    /// </summary>
 61    /// <param name="data">The raw data to extract values from.</param>
 62    /// <param name="offset">The index to start extracting values from.</param>
 63    /// <param name="count">The number of bytes available.</param>
 64    public void SetData(byte[] data, int offset, int count)
 65    {
 66      if (data == null) {
 67        throw new ArgumentNullException(nameof(data));
 68      }
 69
 70      _data = new byte[count];
 71      Array.Copy(data, offset, _data, 0, count);
 72    }
 73
 74    /// <summary>
 75    /// Get the binary data representing this instance.
 76    /// </summary>
 77    /// <returns>The raw binary data representing this instance.</returns>
 78    public byte[] GetData()
 79    {
 80      return _data;
 81    }
 82
 83    #endregion
 84
 85    /// <summary>
 86    /// Get /set the binary data representing this instance.
 87    /// </summary>
 88    /// <returns>The raw binary data representing this instance.</returns>
 89    public byte[] Data {
 90      get { return _data; }
 91      set { _data = value; }
 92    }
 93
 94    #region Instance Fields
 95    /// <summary>
 96    /// The tag ID for this instance.
 97    /// </summary>
 98    short _tag;
 99
 100    byte[] _data;
 101    #endregion
 102  }
 103
 104  /// <summary>
 105  /// Class representing extended unix date time values.
 106  /// </summary>
 107  public class ExtendedUnixData : ITaggedData
 108  {
 109    /// <summary>
 110    /// Flags indicate which values are included in this instance.
 111    /// </summary>
 112    [Flags]
 113    public enum Flags : byte
 114    {
 115      /// <summary>
 116      /// The modification time is included
 117      /// </summary>
 118      ModificationTime = 0x01,
 119
 120      /// <summary>
 121      /// The access time is included
 122      /// </summary>
 123      AccessTime = 0x02,
 124
 125      /// <summary>
 126      /// The create time is included.
 127      /// </summary>
 128      CreateTime = 0x04,
 129    }
 130
 131    #region ITaggedData Members
 132
 133    /// <summary>
 134    /// Get the ID
 135    /// </summary>
 136    public short TagID {
 137      get { return 0x5455; }
 138    }
 139
 140    /// <summary>
 141    /// Set the data from the raw values provided.
 142    /// </summary>
 143    /// <param name="data">The raw data to extract values from.</param>
 144    /// <param name="index">The index to start extracting values from.</param>
 145    /// <param name="count">The number of bytes available.</param>
 146    public void SetData(byte[] data, int index, int count)
 147    {
 148      using (MemoryStream ms = new MemoryStream(data, index, count, false))
 149      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 150        // bit 0           if set, modification time is present
 151        // bit 1           if set, access time is present
 152        // bit 2           if set, creation time is present
 153
 154        _flags = (Flags)helperStream.ReadByte();
 155        if (((_flags & Flags.ModificationTime) != 0))
 156        {
 157          int iTime = helperStream.ReadLEInt();
 158
 159          _modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 160            new TimeSpan(0, 0, 0, iTime, 0);
 161
 162          // Central-header version is truncated after modification time
 163          if (count <= 5) return;
 164        }
 165
 166        if ((_flags & Flags.AccessTime) != 0) {
 167          int iTime = helperStream.ReadLEInt();
 168
 169          _lastAccessTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 170            new TimeSpan(0, 0, 0, iTime, 0);
 171        }
 172
 173        if ((_flags & Flags.CreateTime) != 0) {
 174          int iTime = helperStream.ReadLEInt();
 175
 176          _createTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 177            new TimeSpan(0, 0, 0, iTime, 0);
 178        }
 179      }
 180    }
 181
 182    /// <summary>
 183    /// Get the binary data representing this instance.
 184    /// </summary>
 185    /// <returns>The raw binary data representing this instance.</returns>
 186    public byte[] GetData()
 187    {
 188      using (MemoryStream ms = new MemoryStream())
 189      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 190        helperStream.IsStreamOwner = false;
 191        helperStream.WriteByte((byte)_flags);     // Flags
 192        if ((_flags & Flags.ModificationTime) != 0) {
 193          TimeSpan span = _modificationTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 194          var seconds = (int)span.TotalSeconds;
 195          helperStream.WriteLEInt(seconds);
 196        }
 197        if ((_flags & Flags.AccessTime) != 0) {
 198          TimeSpan span = _lastAccessTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 199          var seconds = (int)span.TotalSeconds;
 200          helperStream.WriteLEInt(seconds);
 201        }
 202        if ((_flags & Flags.CreateTime) != 0) {
 203          TimeSpan span = _createTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 204          var seconds = (int)span.TotalSeconds;
 205          helperStream.WriteLEInt(seconds);
 206        }
 207        return ms.ToArray();
 208      }
 209    }
 210
 211    #endregion
 212
 213    /// <summary>
 214    /// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>
 215    /// </summary>
 216    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 217    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 218    /// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,
 219    /// which is the number of seconds since 1970-01-01.
 220    /// Being 32 bits means the values here cover a range of about 136 years.
 221    /// The minimum representable time is 1901-12-13 20:45:52,
 222    /// and the maximum representable time is 2038-01-19 03:14:07.
 223    /// </remarks>
 224    public static bool IsValidValue(DateTime value)
 225    {
 226      return ((value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||
 227          (value <= new DateTime(2038, 1, 19, 03, 14, 07)));
 228    }
 229
 230    /// <summary>
 231    /// Get /set the Modification Time
 232    /// </summary>
 233    /// <exception cref="ArgumentOutOfRangeException"></exception>
 234    /// <seealso cref="IsValidValue"></seealso>
 235    public DateTime ModificationTime {
 236      get { return _modificationTime; }
 237      set {
 238        if (!IsValidValue(value)) {
 239          throw new ArgumentOutOfRangeException(nameof(value));
 240        }
 241
 242        _flags |= Flags.ModificationTime;
 243        _modificationTime = value;
 244      }
 245    }
 246
 247    /// <summary>
 248    /// Get / set the Access Time
 249    /// </summary>
 250    /// <exception cref="ArgumentOutOfRangeException"></exception>
 251    /// <seealso cref="IsValidValue"></seealso>
 252    public DateTime AccessTime {
 253      get { return _lastAccessTime; }
 254      set {
 255        if (!IsValidValue(value)) {
 256          throw new ArgumentOutOfRangeException(nameof(value));
 257        }
 258
 259        _flags |= Flags.AccessTime;
 260        _lastAccessTime = value;
 261      }
 262    }
 263
 264    /// <summary>
 265    /// Get / Set the Create Time
 266    /// </summary>
 267    /// <exception cref="ArgumentOutOfRangeException"></exception>
 268    /// <seealso cref="IsValidValue"></seealso>
 269    public DateTime CreateTime {
 270      get { return _createTime; }
 271      set {
 272        if (!IsValidValue(value)) {
 273          throw new ArgumentOutOfRangeException(nameof(value));
 274        }
 275
 276        _flags |= Flags.CreateTime;
 277        _createTime = value;
 278      }
 279    }
 280
 281    /// <summary>
 282    /// Get/set the <see cref="Flags">values</see> to include.
 283    /// </summary>
 284    public Flags Include
 285    {
 286      get { return _flags; }
 287      set { _flags = value; }
 288    }
 289
 290    #region Instance Fields
 291    Flags _flags;
 292    DateTime _modificationTime = new DateTime(1970, 1, 1);
 293    DateTime _lastAccessTime = new DateTime(1970, 1, 1);
 294    DateTime _createTime = new DateTime(1970, 1, 1);
 295    #endregion
 296  }
 297
 298  /// <summary>
 299  /// Class handling NT date time values.
 300  /// </summary>
 301  public class NTTaggedData : ITaggedData
 302  {
 303    /// <summary>
 304    /// Get the ID for this tagged data value.
 305    /// </summary>
 306    public short TagID {
 1307      get { return 10; }
 308    }
 309
 310    /// <summary>
 311    /// Set the data from the raw values provided.
 312    /// </summary>
 313    /// <param name="data">The raw data to extract values from.</param>
 314    /// <param name="index">The index to start extracting values from.</param>
 315    /// <param name="count">The number of bytes available.</param>
 316    public void SetData(byte[] data, int index, int count)
 317    {
 1318      using (MemoryStream ms = new MemoryStream(data, index, count, false))
 1319      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 1320        helperStream.ReadLEInt(); // Reserved
 1321         while (helperStream.Position < helperStream.Length) {
 1322          int ntfsTag = helperStream.ReadLEShort();
 1323          int ntfsLength = helperStream.ReadLEShort();
 1324           if (ntfsTag == 1) {
 1325             if (ntfsLength >= 24) {
 1326              long lastModificationTicks = helperStream.ReadLELong();
 1327              _lastModificationTime = DateTime.FromFileTimeUtc(lastModificationTicks);
 328
 1329              long lastAccessTicks = helperStream.ReadLELong();
 1330              _lastAccessTime = DateTime.FromFileTimeUtc(lastAccessTicks);
 331
 1332              long createTimeTicks = helperStream.ReadLELong();
 1333              _createTime = DateTime.FromFileTimeUtc(createTimeTicks);
 334            }
 1335            break;
 336          } else {
 337            // An unknown NTFS tag so simply skip it.
 0338            helperStream.Seek(ntfsLength, SeekOrigin.Current);
 339          }
 340        }
 0341      }
 1342    }
 343
 344    /// <summary>
 345    /// Get the binary data representing this instance.
 346    /// </summary>
 347    /// <returns>The raw binary data representing this instance.</returns>
 348    public byte[] GetData()
 349    {
 2350      using (MemoryStream ms = new MemoryStream())
 2351      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 2352        helperStream.IsStreamOwner = false;
 2353        helperStream.WriteLEInt(0);       // Reserved
 2354        helperStream.WriteLEShort(1);     // Tag
 2355        helperStream.WriteLEShort(24);    // Length = 3 x 8.
 2356        helperStream.WriteLELong(_lastModificationTime.ToFileTimeUtc());
 2357        helperStream.WriteLELong(_lastAccessTime.ToFileTimeUtc());
 2358        helperStream.WriteLELong(_createTime.ToFileTimeUtc());
 2359        return ms.ToArray();
 360      }
 2361    }
 362
 363    /// <summary>
 364    /// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>
 365    /// </summary>
 366    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 367    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 368    /// <remarks>
 369    /// NTFS filetimes are 64-bit unsigned integers, stored in Intel
 370    /// (least significant byte first) byte order. They determine the
 371    /// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
 372    /// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit
 373    /// </remarks>
 374    public static bool IsValidValue(DateTime value)
 375    {
 3376      bool result = true;
 377      try {
 3378        value.ToFileTimeUtc();
 3379      } catch {
 0380        result = false;
 0381      }
 3382      return result;
 383    }
 384
 385    /// <summary>
 386    /// Get/set the <see cref="DateTime">last modification time</see>.
 387    /// </summary>
 388    public DateTime LastModificationTime {
 4389      get { return _lastModificationTime; }
 390      set {
 1391         if (!IsValidValue(value)) {
 0392          throw new ArgumentOutOfRangeException(nameof(value));
 393        }
 1394        _lastModificationTime = value;
 1395      }
 396    }
 397
 398    /// <summary>
 399    /// Get /set the <see cref="DateTime">create time</see>
 400    /// </summary>
 401    public DateTime CreateTime {
 0402      get { return _createTime; }
 403      set {
 1404         if (!IsValidValue(value)) {
 0405          throw new ArgumentOutOfRangeException(nameof(value));
 406        }
 1407        _createTime = value;
 1408      }
 409    }
 410
 411    /// <summary>
 412    /// Get /set the <see cref="DateTime">last access time</see>.
 413    /// </summary>
 414    public DateTime LastAccessTime {
 0415      get { return _lastAccessTime; }
 416      set {
 1417         if (!IsValidValue(value)) {
 0418          throw new ArgumentOutOfRangeException(nameof(value));
 419        }
 1420        _lastAccessTime = value;
 1421      }
 422    }
 423
 424    #region Instance Fields
 1425    DateTime _lastAccessTime = DateTime.FromFileTimeUtc(0);
 1426    DateTime _lastModificationTime = DateTime.FromFileTimeUtc(0);
 1427    DateTime _createTime = DateTime.FromFileTimeUtc(0);
 428    #endregion
 429  }
 430
 431  /// <summary>
 432  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.
 433  /// </summary>
 434  interface ITaggedDataFactory
 435  {
 436    /// <summary>
 437    /// Get data for a specific tag value.
 438    /// </summary>
 439    /// <param name="tag">The tag ID to find.</param>
 440    /// <param name="data">The data to search.</param>
 441    /// <param name="offset">The offset to begin extracting data from.</param>
 442    /// <param name="count">The number of bytes to extract.</param>
 443    /// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>
 444    ITaggedData Create(short tag, byte[] data, int offset, int count);
 445  }
 446
 447  ///
 448  /// <summary>
 449  /// A class to handle the extra data field for Zip entries
 450  /// </summary>
 451  /// <remarks>
 452  /// Extra data contains 0 or more values each prefixed by a header tag and length.
 453  /// They contain zero or more bytes of actual data.
 454  /// The data is held internally using a copy on write strategy.  This is more efficient but
 455  /// means that for extra data created by passing in data can have the values modified by the caller
 456  /// in some circumstances.
 457  /// </remarks>
 458  sealed public class ZipExtraData : IDisposable
 459  {
 460    #region Constructors
 461    /// <summary>
 462    /// Initialise a default instance.
 463    /// </summary>
 464    public ZipExtraData()
 465    {
 466      Clear();
 467    }
 468
 469    /// <summary>
 470    /// Initialise with known extra data.
 471    /// </summary>
 472    /// <param name="data">The extra data.</param>
 473    public ZipExtraData(byte[] data)
 474    {
 475      if (data == null) {
 476        _data = new byte[0];
 477      } else {
 478        _data = data;
 479      }
 480    }
 481    #endregion
 482
 483    /// <summary>
 484    /// Get the raw extra data value
 485    /// </summary>
 486    /// <returns>Returns the raw byte[] extra data this instance represents.</returns>
 487    public byte[] GetEntryData()
 488    {
 489      if (Length > ushort.MaxValue) {
 490        throw new ZipException("Data exceeds maximum length");
 491      }
 492
 493      return (byte[])_data.Clone();
 494    }
 495
 496    /// <summary>
 497    /// Clear the stored data.
 498    /// </summary>
 499    public void Clear()
 500    {
 501      if ((_data == null) || (_data.Length != 0)) {
 502        _data = new byte[0];
 503      }
 504    }
 505
 506    /// <summary>
 507    /// Gets the current extra data length.
 508    /// </summary>
 509    public int Length {
 510      get { return _data.Length; }
 511    }
 512
 513    /// <summary>
 514    /// Get a read-only <see cref="Stream"/> for the associated tag.
 515    /// </summary>
 516    /// <param name="tag">The tag to locate data for.</param>
 517    /// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>
 518    public Stream GetStreamForTag(int tag)
 519    {
 520      Stream result = null;
 521      if (Find(tag)) {
 522        result = new MemoryStream(_data, _index, _readValueLength, false);
 523      }
 524      return result;
 525    }
 526
 527    /// <summary>
 528    /// Get the <see cref="ITaggedData">tagged data</see> for a tag.
 529    /// </summary>
 530    /// <typeparam name="T">The tag to search for.</typeparam>
 531    /// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>
 532    public T GetData<T>()
 533      where T : class, ITaggedData, new()
 534    {
 535      T result = new T();
 536      if (Find(result.TagID))
 537      {
 538        result.SetData(_data, _readValueStart, _readValueLength);
 539        return result;
 540      }
 541      else return null;
 542    }
 543
 544    /// <summary>
 545    /// Get the length of the last value found by <see cref="Find"/>
 546    /// </summary>
 547    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.</remarks>
 548    public int ValueLength {
 549      get { return _readValueLength; }
 550    }
 551
 552    /// <summary>
 553    /// Get the index for the current read value.
 554    /// </summary>
 555    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.
 556    /// Initially the result will be the index of the first byte of actual data.  The value is updated after calls to
 557    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>
 558    public int CurrentReadIndex {
 559      get { return _index; }
 560    }
 561
 562    /// <summary>
 563    /// Get the number of bytes remaining to be read for the current value;
 564    /// </summary>
 565    public int UnreadCount {
 566      get {
 567        if ((_readValueStart > _data.Length) ||
 568          (_readValueStart < 4)) {
 569          throw new ZipException("Find must be called before calling a Read method");
 570        }
 571
 572        return _readValueStart + _readValueLength - _index;
 573      }
 574    }
 575
 576    /// <summary>
 577    /// Find an extra data value
 578    /// </summary>
 579    /// <param name="headerID">The identifier for the value to find.</param>
 580    /// <returns>Returns true if the value was found; false otherwise.</returns>
 581    public bool Find(int headerID)
 582    {
 583      _readValueStart = _data.Length;
 584      _readValueLength = 0;
 585      _index = 0;
 586
 587      int localLength = _readValueStart;
 588      int localTag = headerID - 1;
 589
 590      // Trailing bytes that cant make up an entry (as there arent enough
 591      // bytes for a tag and length) are ignored!
 592      while ((localTag != headerID) && (_index < _data.Length - 3)) {
 593        localTag = ReadShortInternal();
 594        localLength = ReadShortInternal();
 595        if (localTag != headerID) {
 596          _index += localLength;
 597        }
 598      }
 599
 600      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);
 601
 602      if (result) {
 603        _readValueStart = _index;
 604        _readValueLength = localLength;
 605      }
 606
 607      return result;
 608    }
 609
 610    /// <summary>
 611    /// Add a new entry to extra data.
 612    /// </summary>
 613    /// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>
 614    public void AddEntry(ITaggedData taggedData)
 615    {
 616      if (taggedData == null) {
 617        throw new ArgumentNullException(nameof(taggedData));
 618      }
 619      AddEntry(taggedData.TagID, taggedData.GetData());
 620    }
 621
 622    /// <summary>
 623    /// Add a new entry to extra data
 624    /// </summary>
 625    /// <param name="headerID">The ID for this entry.</param>
 626    /// <param name="fieldData">The data to add.</param>
 627    /// <remarks>If the ID already exists its contents are replaced.</remarks>
 628    public void AddEntry(int headerID, byte[] fieldData)
 629    {
 630      if ((headerID > ushort.MaxValue) || (headerID < 0)) {
 631        throw new ArgumentOutOfRangeException(nameof(headerID));
 632      }
 633
 634      int addLength = (fieldData == null) ? 0 : fieldData.Length;
 635
 636      if (addLength > ushort.MaxValue) {
 637        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");
 638      }
 639
 640      // Test for new length before adjusting data.
 641      int newLength = _data.Length + addLength + 4;
 642
 643      if (Find(headerID)) {
 644        newLength -= (ValueLength + 4);
 645      }
 646
 647      if (newLength > ushort.MaxValue) {
 648        throw new ZipException("Data exceeds maximum length");
 649      }
 650
 651      Delete(headerID);
 652
 653      byte[] newData = new byte[newLength];
 654      _data.CopyTo(newData, 0);
 655      int index = _data.Length;
 656      _data = newData;
 657      SetShort(ref index, headerID);
 658      SetShort(ref index, addLength);
 659      if (fieldData != null) {
 660        fieldData.CopyTo(newData, index);
 661      }
 662    }
 663
 664    /// <summary>
 665    /// Start adding a new entry.
 666    /// </summary>
 667    /// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see
 668    /// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>
 669    /// <seealso cref="AddEntry(ITaggedData)"/>
 670    public void StartNewEntry()
 671    {
 672      _newEntry = new MemoryStream();
 673    }
 674
 675    /// <summary>
 676    /// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.
 677    /// </summary>
 678    /// <param name="headerID">The identifier to use for this entry.</param>
 679    public void AddNewEntry(int headerID)
 680    {
 681      byte[] newData = _newEntry.ToArray();
 682      _newEntry = null;
 683      AddEntry(headerID, newData);
 684    }
 685
 686    /// <summary>
 687    /// Add a byte of data to the pending new entry.
 688    /// </summary>
 689    /// <param name="data">The byte to add.</param>
 690    /// <seealso cref="StartNewEntry"/>
 691    public void AddData(byte data)
 692    {
 693      _newEntry.WriteByte(data);
 694    }
 695
 696    /// <summary>
 697    /// Add data to a pending new entry.
 698    /// </summary>
 699    /// <param name="data">The data to add.</param>
 700    /// <seealso cref="StartNewEntry"/>
 701    public void AddData(byte[] data)
 702    {
 703      if (data == null) {
 704        throw new ArgumentNullException(nameof(data));
 705      }
 706
 707      _newEntry.Write(data, 0, data.Length);
 708    }
 709
 710    /// <summary>
 711    /// Add a short value in little endian order to the pending new entry.
 712    /// </summary>
 713    /// <param name="toAdd">The data to add.</param>
 714    /// <seealso cref="StartNewEntry"/>
 715    public void AddLeShort(int toAdd)
 716    {
 717      unchecked {
 718        _newEntry.WriteByte((byte)toAdd);
 719        _newEntry.WriteByte((byte)(toAdd >> 8));
 720      }
 721    }
 722
 723    /// <summary>
 724    /// Add an integer value in little endian order to the pending new entry.
 725    /// </summary>
 726    /// <param name="toAdd">The data to add.</param>
 727    /// <seealso cref="StartNewEntry"/>
 728    public void AddLeInt(int toAdd)
 729    {
 730      unchecked {
 731        AddLeShort((short)toAdd);
 732        AddLeShort((short)(toAdd >> 16));
 733      }
 734    }
 735
 736    /// <summary>
 737    /// Add a long value in little endian order to the pending new entry.
 738    /// </summary>
 739    /// <param name="toAdd">The data to add.</param>
 740    /// <seealso cref="StartNewEntry"/>
 741    public void AddLeLong(long toAdd)
 742    {
 743      unchecked {
 744        AddLeInt((int)(toAdd & 0xffffffff));
 745        AddLeInt((int)(toAdd >> 32));
 746      }
 747    }
 748
 749    /// <summary>
 750    /// Delete an extra data field.
 751    /// </summary>
 752    /// <param name="headerID">The identifier of the field to delete.</param>
 753    /// <returns>Returns true if the field was found and deleted.</returns>
 754    public bool Delete(int headerID)
 755    {
 756      bool result = false;
 757
 758      if (Find(headerID)) {
 759        result = true;
 760        int trueStart = _readValueStart - 4;
 761
 762        byte[] newData = new byte[_data.Length - (ValueLength + 4)];
 763        Array.Copy(_data, 0, newData, 0, trueStart);
 764
 765        int trueEnd = trueStart + ValueLength + 4;
 766        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);
 767        _data = newData;
 768      }
 769      return result;
 770    }
 771
 772    #region Reading Support
 773    /// <summary>
 774    /// Read a long in little endian form from the last <see cref="Find">found</see> data value
 775    /// </summary>
 776    /// <returns>Returns the long value read.</returns>
 777    public long ReadLong()
 778    {
 779      ReadCheck(8);
 780      return (ReadInt() & 0xffffffff) | (((long)ReadInt()) << 32);
 781    }
 782
 783    /// <summary>
 784    /// Read an integer in little endian form from the last <see cref="Find">found</see> data value.
 785    /// </summary>
 786    /// <returns>Returns the integer read.</returns>
 787    public int ReadInt()
 788    {
 789      ReadCheck(4);
 790
 791      int result = _data[_index] + (_data[_index + 1] << 8) +
 792        (_data[_index + 2] << 16) + (_data[_index + 3] << 24);
 793      _index += 4;
 794      return result;
 795    }
 796
 797    /// <summary>
 798    /// Read a short value in little endian form from the last <see cref="Find">found</see> data value.
 799    /// </summary>
 800    /// <returns>Returns the short value read.</returns>
 801    public int ReadShort()
 802    {
 803      ReadCheck(2);
 804      int result = _data[_index] + (_data[_index + 1] << 8);
 805      _index += 2;
 806      return result;
 807    }
 808
 809    /// <summary>
 810    /// Read a byte from an extra data
 811    /// </summary>
 812    /// <returns>The byte value read or -1 if the end of data has been reached.</returns>
 813    public int ReadByte()
 814    {
 815      int result = -1;
 816      if ((_index < _data.Length) && (_readValueStart + _readValueLength > _index)) {
 817        result = _data[_index];
 818        _index += 1;
 819      }
 820      return result;
 821    }
 822
 823    /// <summary>
 824    /// Skip data during reading.
 825    /// </summary>
 826    /// <param name="amount">The number of bytes to skip.</param>
 827    public void Skip(int amount)
 828    {
 829      ReadCheck(amount);
 830      _index += amount;
 831    }
 832
 833    void ReadCheck(int length)
 834    {
 835      if ((_readValueStart > _data.Length) ||
 836        (_readValueStart < 4)) {
 837        throw new ZipException("Find must be called before calling a Read method");
 838      }
 839
 840      if (_index > _readValueStart + _readValueLength - length) {
 841        throw new ZipException("End of extra data");
 842      }
 843
 844      if (_index + length < 4) {
 845        throw new ZipException("Cannot read before start of tag");
 846      }
 847    }
 848
 849    /// <summary>
 850    /// Internal form of <see cref="ReadShort"/> that reads data at any location.
 851    /// </summary>
 852    /// <returns>Returns the short value read.</returns>
 853    int ReadShortInternal()
 854    {
 855      if (_index > _data.Length - 2) {
 856        throw new ZipException("End of extra data");
 857      }
 858
 859      int result = _data[_index] + (_data[_index + 1] << 8);
 860      _index += 2;
 861      return result;
 862    }
 863
 864    void SetShort(ref int index, int source)
 865    {
 866      _data[index] = (byte)source;
 867      _data[index + 1] = (byte)(source >> 8);
 868      index += 2;
 869    }
 870
 871    #endregion
 872
 873    #region IDisposable Members
 874
 875    /// <summary>
 876    /// Dispose of this instance.
 877    /// </summary>
 878    public void Dispose()
 879    {
 880      if (_newEntry != null) {
 881        _newEntry.Close();
 882      }
 883    }
 884
 885    #endregion
 886
 887    #region Instance Fields
 888    int _index;
 889    int _readValueStart;
 890    int _readValueLength;
 891
 892    MemoryStream _newEntry;
 893    byte[] _data;
 894    #endregion
 895  }
 896}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_NameAndSizeFilter.htm b/docs/opencover/ICSharpCode.SharpZipLib_NameAndSizeFilter.htm new file mode 100644 index 000000000..77bfa8bd7 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_NameAndSizeFilter.htm @@ -0,0 +1,323 @@ + + + + +ICSharpCode.SharpZipLib.Core.NameAndSizeFilter - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.NameAndSizeFilter
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\PathFilter.cs
Covered lines:0
Uncovered lines:23
Coverable lines:23
Total lines:280
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
IsMatch(...)300
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\PathFilter.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Core
 5{
 6  /// <summary>
 7  /// PathFilter filters directories and files using a form of <see cref="System.Text.RegularExpressions.Regex">regular 
 8  /// by full path name.
 9  /// See <see cref="NameFilter">NameFilter</see> for more detail on filtering.
 10  /// </summary>
 11  public class PathFilter : IScanFilter
 12  {
 13    #region Constructors
 14    /// <summary>
 15    /// Initialise a new instance of <see cref="PathFilter"></see>.
 16    /// </summary>
 17    /// <param name="filter">The <see cref="NameFilter">filter</see> expression to apply.</param>
 18    public PathFilter(string filter)
 19    {
 20      nameFilter_ = new NameFilter(filter);
 21    }
 22    #endregion
 23
 24    #region IScanFilter Members
 25    /// <summary>
 26    /// Test a name to see if it matches the filter.
 27    /// </summary>
 28    /// <param name="name">The name to test.</param>
 29    /// <returns>True if the name matches, false otherwise.</returns>
 30    /// <remarks><see cref="Path.GetFullPath(string)"/> is used to get the full path before matching.</remarks>
 31    public virtual bool IsMatch(string name)
 32    {
 33      bool result = false;
 34
 35      if (name != null) {
 36        string cooked = (name.Length > 0) ? Path.GetFullPath(name) : "";
 37        result = nameFilter_.IsMatch(cooked);
 38      }
 39      return result;
 40    }
 41
 42    readonly
 43    #endregion
 44
 45    #region Instance Fields
 46    NameFilter nameFilter_;
 47    #endregion
 48  }
 49
 50  /// <summary>
 51  /// ExtendedPathFilter filters based on name, file size, and the last write time of the file.
 52  /// </summary>
 53  /// <remarks>Provides an example of how to customise filtering.</remarks>
 54  public class ExtendedPathFilter : PathFilter
 55  {
 56    #region Constructors
 57    /// <summary>
 58    /// Initialise a new instance of ExtendedPathFilter.
 59    /// </summary>
 60    /// <param name="filter">The filter to apply.</param>
 61    /// <param name="minSize">The minimum file size to include.</param>
 62    /// <param name="maxSize">The maximum file size to include.</param>
 63    public ExtendedPathFilter(string filter,
 64      long minSize, long maxSize)
 65      : base(filter)
 66    {
 67      MinSize = minSize;
 68      MaxSize = maxSize;
 69    }
 70
 71    /// <summary>
 72    /// Initialise a new instance of ExtendedPathFilter.
 73    /// </summary>
 74    /// <param name="filter">The filter to apply.</param>
 75    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
 76    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
 77    public ExtendedPathFilter(string filter,
 78      DateTime minDate, DateTime maxDate)
 79      : base(filter)
 80    {
 81      MinDate = minDate;
 82      MaxDate = maxDate;
 83    }
 84
 85    /// <summary>
 86    /// Initialise a new instance of ExtendedPathFilter.
 87    /// </summary>
 88    /// <param name="filter">The filter to apply.</param>
 89    /// <param name="minSize">The minimum file size to include.</param>
 90    /// <param name="maxSize">The maximum file size to include.</param>
 91    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
 92    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
 93    public ExtendedPathFilter(string filter,
 94      long minSize, long maxSize,
 95      DateTime minDate, DateTime maxDate)
 96      : base(filter)
 97    {
 98      MinSize = minSize;
 99      MaxSize = maxSize;
 100      MinDate = minDate;
 101      MaxDate = maxDate;
 102    }
 103    #endregion
 104
 105    #region IScanFilter Members
 106    /// <summary>
 107    /// Test a filename to see if it matches the filter.
 108    /// </summary>
 109    /// <param name="name">The filename to test.</param>
 110    /// <returns>True if the filter matches, false otherwise.</returns>
 111    /// <exception cref="System.IO.FileNotFoundException">The <see paramref="fileName"/> doesnt exist</exception>
 112    public override bool IsMatch(string name)
 113    {
 114      bool result = base.IsMatch(name);
 115
 116      if (result) {
 117        var fileInfo = new FileInfo(name);
 118        result =
 119          (MinSize <= fileInfo.Length) &&
 120          (MaxSize >= fileInfo.Length) &&
 121          (MinDate <= fileInfo.LastWriteTime) &&
 122          (MaxDate >= fileInfo.LastWriteTime)
 123          ;
 124      }
 125      return result;
 126    }
 127    #endregion
 128
 129    #region Properties
 130    /// <summary>
 131    /// Get/set the minimum size/length for a file that will match this filter.
 132    /// </summary>
 133    /// <remarks>The default value is zero.</remarks>
 134    /// <exception cref="ArgumentOutOfRangeException">value is less than zero; greater than <see cref="MaxSize"/></excep
 135    public long MinSize {
 136      get { return minSize_; }
 137      set {
 138        if ((value < 0) || (maxSize_ < value)) {
 139          throw new ArgumentOutOfRangeException(nameof(value));
 140        }
 141
 142        minSize_ = value;
 143      }
 144    }
 145
 146    /// <summary>
 147    /// Get/set the maximum size/length for a file that will match this filter.
 148    /// </summary>
 149    /// <remarks>The default value is <see cref="System.Int64.MaxValue"/></remarks>
 150    /// <exception cref="ArgumentOutOfRangeException">value is less than zero or less than <see cref="MinSize"/></except
 151    public long MaxSize {
 152      get { return maxSize_; }
 153      set {
 154        if ((value < 0) || (minSize_ > value)) {
 155          throw new ArgumentOutOfRangeException(nameof(value));
 156        }
 157
 158        maxSize_ = value;
 159      }
 160    }
 161
 162    /// <summary>
 163    /// Get/set the minimum <see cref="DateTime"/> value that will match for this filter.
 164    /// </summary>
 165    /// <remarks>Files with a LastWrite time less than this value are excluded by the filter.</remarks>
 166    public DateTime MinDate {
 167      get {
 168        return minDate_;
 169      }
 170
 171      set {
 172        if (value > maxDate_) {
 173          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MaxDate");
 174        }
 175
 176        minDate_ = value;
 177      }
 178    }
 179
 180    /// <summary>
 181    /// Get/set the maximum <see cref="DateTime"/> value that will match for this filter.
 182    /// </summary>
 183    /// <remarks>Files with a LastWrite time greater than this value are excluded by the filter.</remarks>
 184    public DateTime MaxDate {
 185      get {
 186        return maxDate_;
 187      }
 188
 189      set {
 190        if (minDate_ > value) {
 191          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MinDate");
 192        }
 193
 194        maxDate_ = value;
 195      }
 196    }
 197    #endregion
 198
 199    #region Instance Fields
 200    long minSize_;
 201    long maxSize_ = long.MaxValue;
 202    DateTime minDate_ = DateTime.MinValue;
 203    DateTime maxDate_ = DateTime.MaxValue;
 204    #endregion
 205  }
 206
 207  /// <summary>
 208  /// NameAndSizeFilter filters based on name and file size.
 209  /// </summary>
 210  /// <remarks>A sample showing how filters might be extended.</remarks>
 211  [Obsolete("Use ExtendedPathFilter instead")]
 212  public class NameAndSizeFilter : PathFilter
 213  {
 214
 215    /// <summary>
 216    /// Initialise a new instance of NameAndSizeFilter.
 217    /// </summary>
 218    /// <param name="filter">The filter to apply.</param>
 219    /// <param name="minSize">The minimum file size to include.</param>
 220    /// <param name="maxSize">The maximum file size to include.</param>
 221    public NameAndSizeFilter(string filter, long minSize, long maxSize)
 0222      : base(filter)
 223    {
 0224      MinSize = minSize;
 0225      MaxSize = maxSize;
 0226    }
 227
 228    /// <summary>
 229    /// Test a filename to see if it matches the filter.
 230    /// </summary>
 231    /// <param name="name">The filename to test.</param>
 232    /// <returns>True if the filter matches, false otherwise.</returns>
 233    public override bool IsMatch(string name)
 234    {
 0235      bool result = base.IsMatch(name);
 236
 0237       if (result) {
 0238        var fileInfo = new FileInfo(name);
 0239        long length = fileInfo.Length;
 0240        result =
 0241          (MinSize <= length) &&
 0242          (MaxSize >= length);
 243      }
 0244      return result;
 245    }
 246
 247    /// <summary>
 248    /// Get/set the minimum size for a file that will match this filter.
 249    /// </summary>
 250    public long MinSize {
 0251      get { return minSize_; }
 252      set {
 0253         if ((value < 0) || (maxSize_ < value)) {
 0254          throw new ArgumentOutOfRangeException(nameof(value));
 255        }
 256
 0257        minSize_ = value;
 0258      }
 259    }
 260
 261    /// <summary>
 262    /// Get/set the maximum size for a file that will match this filter.
 263    /// </summary>
 264    public long MaxSize {
 0265      get { return maxSize_; }
 266      set {
 0267         if ((value < 0) || (minSize_ > value)) {
 0268          throw new ArgumentOutOfRangeException(nameof(value));
 269        }
 270
 0271        maxSize_ = value;
 0272      }
 273    }
 274
 275    #region Instance Fields
 276    long minSize_;
 0277    long maxSize_ = long.MaxValue;
 278    #endregion
 279  }
 280}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_NameFilter.htm b/docs/opencover/ICSharpCode.SharpZipLib_NameFilter.htm new file mode 100644 index 000000000..86343fd9a --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_NameFilter.htm @@ -0,0 +1,285 @@ + + + + +ICSharpCode.SharpZipLib.Core.NameFilter - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.NameFilter
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\NameFilter.cs
Covered lines:68
Uncovered lines:18
Coverable lines:86
Total lines:235
Line coverage:79%
Branch coverage:73.9%
+

Metrics

+ + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
IsValidExpression(...)100
IsValidFilterExpression(...)78069.23
SplitQuoted(...)89693.33
ToString()100
IsIncluded(...)5100100
IsExcluded(...)45033.33
IsMatch(...)2100100
Compile()87566.67
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\NameFilter.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Text;
 4using System.Text.RegularExpressions;
 5
 6namespace ICSharpCode.SharpZipLib.Core
 7{
 8  /// <summary>
 9  /// NameFilter is a string matching class which allows for both positive and negative
 10  /// matching.
 11  /// A filter is a sequence of independant <see cref="Regex">regular expressions</see> separated by semi-colons ';'.
 12  /// To include a semi-colon it may be quoted as in \;. Each expression can be prefixed by a plus '+' sign or
 13  /// a minus '-' sign to denote the expression is intended to include or exclude names.
 14  /// If neither a plus or minus sign is found include is the default.
 15  /// A given name is tested for inclusion before checking exclusions.  Only names matching an include spec
 16  /// and not matching an exclude spec are deemed to match the filter.
 17  /// An empty filter matches any name.
 18  /// </summary>
 19  /// <example>The following expression includes all name ending in '.dat' with the exception of 'dummy.dat'
 20  /// "+\.dat$;-^dummy\.dat$"
 21  /// </example>
 22  public class NameFilter : IScanFilter
 23  {
 24    #region Constructors
 25    /// <summary>
 26    /// Construct an instance based on the filter expression passed
 27    /// </summary>
 28    /// <param name="filter">The filter expression.</param>
 1129    public NameFilter(string filter)
 30    {
 1131      filter_ = filter;
 1132      inclusions_ = new ArrayList();
 1133      exclusions_ = new ArrayList();
 1134      Compile();
 1135    }
 36    #endregion
 37
 38    /// <summary>
 39    /// Test a string to see if it is a valid regular expression.
 40    /// </summary>
 41    /// <param name="expression">The expression to test.</param>
 42    /// <returns>True if expression is a valid <see cref="System.Text.RegularExpressions.Regex"/> false otherwise.</retu
 43    public static bool IsValidExpression(string expression)
 44    {
 045      bool result = true;
 46      try {
 047        var exp = new Regex(expression, RegexOptions.IgnoreCase | RegexOptions.Singleline);
 048      } catch (ArgumentException) {
 049        result = false;
 050      }
 051      return result;
 52    }
 53
 54    /// <summary>
 55    /// Test an expression to see if it is valid as a filter.
 56    /// </summary>
 57    /// <param name="toTest">The filter expression to test.</param>
 58    /// <returns>True if the expression is valid, false otherwise.</returns>
 59    public static bool IsValidFilterExpression(string toTest)
 60    {
 561      bool result = true;
 62
 63      try {
 564         if (toTest != null) {
 465          string[] items = SplitQuoted(toTest);
 1066           for (int i = 0; i < items.Length; ++i) {
 367             if ((items[i] != null) && (items[i].Length > 0)) {
 68              string toCompile;
 69
 370               if (items[i][0] == '+') {
 071                toCompile = items[i].Substring(1, items[i].Length - 1);
 372               } else if (items[i][0] == '-') {
 073                toCompile = items[i].Substring(1, items[i].Length - 1);
 074              } else {
 375                toCompile = items[i];
 76              }
 77
 378              var testRegex = new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline);
 79            }
 80          }
 81        }
 582      } catch (ArgumentException) {
 283        result = false;
 284      }
 85
 586      return result;
 87    }
 88
 89    /// <summary>
 90    /// Split a string into its component pieces
 91    /// </summary>
 92    /// <param name="original">The original string</param>
 93    /// <returns>Returns an array of <see cref="T:System.String"/> values containing the individual filter elements.</re
 94    public static string[] SplitQuoted(string original)
 95    {
 1396      char escape = '\\';
 1397      char[] separators = { ';' };
 98
 1399      var result = new ArrayList();
 100
 13101       if (!string.IsNullOrEmpty(original)) {
 11102        int endIndex = -1;
 11103        var b = new StringBuilder();
 104
 78105         while (endIndex < original.Length) {
 67106          endIndex += 1;
 67107           if (endIndex >= original.Length) {
 11108            result.Add(b.ToString());
 67109           } else if (original[endIndex] == escape) {
 11110            endIndex += 1;
 11111             if (endIndex >= original.Length) {
 0112              throw new ArgumentException("Missing terminating escape character", nameof(original));
 113            }
 114            // include escape if this is not an escaped separator
 11115             if (Array.IndexOf(separators, original[endIndex]) < 0)
 6116              b.Append(escape);
 117
 11118            b.Append(original[endIndex]);
 11119          } else {
 45120             if (Array.IndexOf(separators, original[endIndex]) >= 0) {
 11121              result.Add(b.ToString());
 11122              b.Length = 0;
 11123            } else {
 34124              b.Append(original[endIndex]);
 125            }
 126          }
 127        }
 128      }
 129
 13130      return (string[])result.ToArray(typeof(string));
 131    }
 132
 133    /// <summary>
 134    /// Convert this filter to its string equivalent.
 135    /// </summary>
 136    /// <returns>The string equivalent for this filter.</returns>
 137    public override string ToString()
 138    {
 0139      return filter_;
 140    }
 141
 142    /// <summary>
 143    /// Test a value to see if it is included by the filter.
 144    /// </summary>
 145    /// <param name="name">The value to test.</param>
 146    /// <returns>True if the value is included, false otherwise.</returns>
 147    public bool IsIncluded(string name)
 148    {
 14149149      bool result = false;
 14149150       if (inclusions_.Count == 0) {
 2151        result = true;
 2152      } else {
 56584153        foreach (Regex r in inclusions_) {
 14147154           if (r.IsMatch(name)) {
 4155            result = true;
 4156            break;
 157          }
 158        }
 159      }
 14149160      return result;
 161    }
 162
 163    /// <summary>
 164    /// Test a value to see if it is excluded by the filter.
 165    /// </summary>
 166    /// <param name="name">The value to test.</param>
 167    /// <returns>True if the value is excluded, false otherwise.</returns>
 168    public bool IsExcluded(string name)
 169    {
 5170      bool result = false;
 10171      foreach (Regex r in exclusions_) {
 0172         if (r.IsMatch(name)) {
 0173          result = true;
 0174          break;
 175        }
 176      }
 5177      return result;
 178    }
 179
 180    #region IScanFilter Members
 181    /// <summary>
 182    /// Test a value to see if it matches the filter.
 183    /// </summary>
 184    /// <param name="name">The value to test.</param>
 185    /// <returns>True if the value matches, false otherwise.</returns>
 186    public bool IsMatch(string name)
 187    {
 14148188      return (IsIncluded(name) && !IsExcluded(name));
 189    }
 190    #endregion
 191
 192    /// <summary>
 193    /// Compile this filter.
 194    /// </summary>
 195    void Compile()
 196    {
 197      // TODO: Check to see if combining RE's makes it faster/smaller.
 198      // simple scheme would be to have one RE for inclusion and one for exclusion.
 11199       if (filter_ == null) {
 6200        return;
 201      }
 202
 5203      string[] items = SplitQuoted(filter_);
 20204       for (int i = 0; i < items.Length; ++i) {
 5205         if ((items[i] != null) && (items[i].Length > 0)) {
 5206          bool include = (items[i][0] != '-');
 207          string toCompile;
 208
 5209           if (items[i][0] == '+') {
 0210            toCompile = items[i].Substring(1, items[i].Length - 1);
 5211           } else if (items[i][0] == '-') {
 0212            toCompile = items[i].Substring(1, items[i].Length - 1);
 0213          } else {
 5214            toCompile = items[i];
 215          }
 216
 217          // NOTE: Regular expressions can fail to compile here for a number of reasons that cause an exception
 218          // these are left unhandled here as the caller is responsible for ensuring all is valid.
 219          // several functions IsValidFilterExpression and IsValidExpression are provided for such checking
 5220           if (include) {
 5221            inclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleli
 5222          } else {
 0223            exclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleli
 224          }
 225        }
 226      }
 5227    }
 228
 229    #region Instance Fields
 230    string filter_;
 231    ArrayList inclusions_;
 232    ArrayList exclusions_;
 233    #endregion
 234  }
 235}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_OutputWindow.htm b/docs/opencover/ICSharpCode.SharpZipLib_OutputWindow.htm new file mode 100644 index 000000000..98eea7b90 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_OutputWindow.htm @@ -0,0 +1,246 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\OutputWindow.cs
Covered lines:46
Uncovered lines:20
Coverable lines:66
Total lines:195
Line coverage:69.6%
Branch coverage:53.3%
+

Metrics

+ + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
Write(...)28066.67
SlowRepeat(...)200
Repeat(...)678.5772.73
CopyStored(...)310080
CopyDict(...)400
GetFreeSpace()1100100
GetAvailable()1100100
CopyOutput(...)493.7585.71
Reset()1100100
.ctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\OutputWindow.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
 4{
 5  /// <summary>
 6  /// Contains the output from the Inflation process.
 7  /// We need to have a window so that we can refer backwards into the output stream
 8  /// to repeat stuff.<br/>
 9  /// Author of the original java version : John Leuner
 10  /// </summary>
 11  public class OutputWindow
 12  {
 13    #region Constants
 14    const int WindowSize = 1 << 15;
 15    const int WindowMask = WindowSize - 1;
 16    #endregion
 17
 18    #region Instance Fields
 43519    byte[] window = new byte[WindowSize]; //The window is 2^15 bytes
 20    int windowEnd;
 21    int windowFilled;
 22    #endregion
 23
 24    /// <summary>
 25    /// Write a byte to this output window
 26    /// </summary>
 27    /// <param name="value">value to write</param>
 28    /// <exception cref="InvalidOperationException">
 29    /// if window is full
 30    /// </exception>
 31    public void Write(int value)
 32    {
 922933       if (windowFilled++ == WindowSize) {
 034        throw new InvalidOperationException("Window full");
 35      }
 922936      window[windowEnd++] = (byte)value;
 922937      windowEnd &= WindowMask;
 922938    }
 39
 40
 41    private void SlowRepeat(int repStart, int length, int distance)
 42    {
 043       while (length-- > 0) {
 044        window[windowEnd++] = window[repStart++];
 045        windowEnd &= WindowMask;
 046        repStart &= WindowMask;
 47      }
 048    }
 49
 50    /// <summary>
 51    /// Append a byte pattern already in the window itself
 52    /// </summary>
 53    /// <param name="length">length of pattern to copy</param>
 54    /// <param name="distance">distance from end of window pattern occurs</param>
 55    /// <exception cref="InvalidOperationException">
 56    /// If the repeated data overflows the window
 57    /// </exception>
 58    public void Repeat(int length, int distance)
 59    {
 9760       if ((windowFilled += length) > WindowSize) {
 061        throw new InvalidOperationException("Window full");
 62      }
 63
 9764      int repStart = (windowEnd - distance) & WindowMask;
 9765      int border = WindowSize - length;
 9766       if ((repStart <= border) && (windowEnd < border)) {
 9767         if (length <= distance) {
 3768          System.Array.Copy(window, repStart, window, windowEnd, length);
 3769          windowEnd += length;
 3770        } else {
 71          // We have to copy manually, since the repeat pattern overlaps.
 1146172           while (length-- > 0) {
 1140173            window[windowEnd++] = window[repStart++];
 74          }
 75        }
 6076      } else {
 077        SlowRepeat(repStart, length, distance);
 78      }
 079    }
 80
 81    /// <summary>
 82    /// Copy from input manipulator to internal window
 83    /// </summary>
 84    /// <param name="input">source of data</param>
 85    /// <param name="length">length of data to copy</param>
 86    /// <returns>the number of bytes copied</returns>
 87    public int CopyStored(StreamManipulator input, int length)
 88    {
 228089      length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);
 90      int copied;
 91
 228092      int tailLen = WindowSize - windowEnd;
 228093       if (length > tailLen) {
 9694        copied = input.CopyBytes(window, windowEnd, tailLen);
 9695         if (copied == tailLen) {
 9696          copied += input.CopyBytes(window, 0, length - tailLen);
 97        }
 9698      } else {
 218499        copied = input.CopyBytes(window, windowEnd, length);
 100      }
 101
 2280102      windowEnd = (windowEnd + copied) & WindowMask;
 2280103      windowFilled += copied;
 2280104      return copied;
 105    }
 106
 107    /// <summary>
 108    /// Copy dictionary to window
 109    /// </summary>
 110    /// <param name="dictionary">source dictionary</param>
 111    /// <param name="offset">offset of start in source dictionary</param>
 112    /// <param name="length">length of dictionary</param>
 113    /// <exception cref="InvalidOperationException">
 114    /// If window isnt empty
 115    /// </exception>
 116    public void CopyDict(byte[] dictionary, int offset, int length)
 117    {
 0118       if (dictionary == null) {
 0119        throw new ArgumentNullException(nameof(dictionary));
 120      }
 121
 0122       if (windowFilled > 0) {
 0123        throw new InvalidOperationException();
 124      }
 125
 0126       if (length > WindowSize) {
 0127        offset += length - WindowSize;
 0128        length = WindowSize;
 129      }
 0130      System.Array.Copy(dictionary, offset, window, 0, length);
 0131      windowEnd = length & WindowMask;
 0132    }
 133
 134    /// <summary>
 135    /// Get remaining unfilled space in window
 136    /// </summary>
 137    /// <returns>Number of bytes left in window</returns>
 138    public int GetFreeSpace()
 139    {
 371140      return WindowSize - windowFilled;
 141    }
 142
 143    /// <summary>
 144    /// Get bytes available for output in window
 145    /// </summary>
 146    /// <returns>Number of bytes filled</returns>
 147    public int GetAvailable()
 148    {
 3783149      return windowFilled;
 150    }
 151
 152    /// <summary>
 153    /// Copy contents of window to output
 154    /// </summary>
 155    /// <param name="output">buffer to copy to</param>
 156    /// <param name="offset">offset to start at</param>
 157    /// <param name="len">number of bytes to count</param>
 158    /// <returns>The number of bytes copied</returns>
 159    /// <exception cref="InvalidOperationException">
 160    /// If a window underflow occurs
 161    /// </exception>
 162    public int CopyOutput(byte[] output, int offset, int len)
 163    {
 4523164      int copyEnd = windowEnd;
 4523165       if (len > windowFilled) {
 4401166        len = windowFilled;
 4401167      } else {
 122168        copyEnd = (windowEnd - windowFilled + len) & WindowMask;
 169      }
 170
 4523171      int copied = len;
 4523172      int tailLen = len - copyEnd;
 173
 4523174       if (tailLen > 0) {
 102175        System.Array.Copy(window, WindowSize - tailLen, output, offset, tailLen);
 102176        offset += tailLen;
 102177        len = copyEnd;
 178      }
 4523179      System.Array.Copy(window, copyEnd - len, output, offset, len);
 4523180      windowFilled -= copied;
 4523181       if (windowFilled < 0) {
 0182        throw new InvalidOperationException();
 183      }
 4523184      return copied;
 185    }
 186
 187    /// <summary>
 188    /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0
 189    /// </summary>
 190    public void Reset()
 191    {
 41192      windowFilled = windowEnd = 0;
 41193    }
 194  }
 195}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_PathFilter.htm b/docs/opencover/ICSharpCode.SharpZipLib_PathFilter.htm new file mode 100644 index 000000000..b72a9e78e --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_PathFilter.htm @@ -0,0 +1,323 @@ + + + + +ICSharpCode.SharpZipLib.Core.PathFilter - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.PathFilter
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\PathFilter.cs
Covered lines:8
Uncovered lines:0
Coverable lines:8
Total lines:280
Line coverage:100%
Branch coverage:50%
+

Metrics

+ + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
IsMatch(...)410060
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\PathFilter.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Core
 5{
 6  /// <summary>
 7  /// PathFilter filters directories and files using a form of <see cref="System.Text.RegularExpressions.Regex">regular 
 8  /// by full path name.
 9  /// See <see cref="NameFilter">NameFilter</see> for more detail on filtering.
 10  /// </summary>
 11  public class PathFilter : IScanFilter
 12  {
 13    #region Constructors
 14    /// <summary>
 15    /// Initialise a new instance of <see cref="PathFilter"></see>.
 16    /// </summary>
 17    /// <param name="filter">The <see cref="NameFilter">filter</see> expression to apply.</param>
 818    public PathFilter(string filter)
 19    {
 820      nameFilter_ = new NameFilter(filter);
 821    }
 22    #endregion
 23
 24    #region IScanFilter Members
 25    /// <summary>
 26    /// Test a name to see if it matches the filter.
 27    /// </summary>
 28    /// <param name="name">The name to test.</param>
 29    /// <returns>True if the name matches, false otherwise.</returns>
 30    /// <remarks><see cref="Path.GetFullPath(string)"/> is used to get the full path before matching.</remarks>
 31    public virtual bool IsMatch(string name)
 32    {
 1414733      bool result = false;
 34
 1414735       if (name != null) {
 1414736         string cooked = (name.Length > 0) ? Path.GetFullPath(name) : "";
 1414737        result = nameFilter_.IsMatch(cooked);
 38      }
 1414739      return result;
 40    }
 41
 42    readonly
 43    #endregion
 44
 45    #region Instance Fields
 46    NameFilter nameFilter_;
 47    #endregion
 48  }
 49
 50  /// <summary>
 51  /// ExtendedPathFilter filters based on name, file size, and the last write time of the file.
 52  /// </summary>
 53  /// <remarks>Provides an example of how to customise filtering.</remarks>
 54  public class ExtendedPathFilter : PathFilter
 55  {
 56    #region Constructors
 57    /// <summary>
 58    /// Initialise a new instance of ExtendedPathFilter.
 59    /// </summary>
 60    /// <param name="filter">The filter to apply.</param>
 61    /// <param name="minSize">The minimum file size to include.</param>
 62    /// <param name="maxSize">The maximum file size to include.</param>
 63    public ExtendedPathFilter(string filter,
 64      long minSize, long maxSize)
 65      : base(filter)
 66    {
 67      MinSize = minSize;
 68      MaxSize = maxSize;
 69    }
 70
 71    /// <summary>
 72    /// Initialise a new instance of ExtendedPathFilter.
 73    /// </summary>
 74    /// <param name="filter">The filter to apply.</param>
 75    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
 76    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
 77    public ExtendedPathFilter(string filter,
 78      DateTime minDate, DateTime maxDate)
 79      : base(filter)
 80    {
 81      MinDate = minDate;
 82      MaxDate = maxDate;
 83    }
 84
 85    /// <summary>
 86    /// Initialise a new instance of ExtendedPathFilter.
 87    /// </summary>
 88    /// <param name="filter">The filter to apply.</param>
 89    /// <param name="minSize">The minimum file size to include.</param>
 90    /// <param name="maxSize">The maximum file size to include.</param>
 91    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
 92    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
 93    public ExtendedPathFilter(string filter,
 94      long minSize, long maxSize,
 95      DateTime minDate, DateTime maxDate)
 96      : base(filter)
 97    {
 98      MinSize = minSize;
 99      MaxSize = maxSize;
 100      MinDate = minDate;
 101      MaxDate = maxDate;
 102    }
 103    #endregion
 104
 105    #region IScanFilter Members
 106    /// <summary>
 107    /// Test a filename to see if it matches the filter.
 108    /// </summary>
 109    /// <param name="name">The filename to test.</param>
 110    /// <returns>True if the filter matches, false otherwise.</returns>
 111    /// <exception cref="System.IO.FileNotFoundException">The <see paramref="fileName"/> doesnt exist</exception>
 112    public override bool IsMatch(string name)
 113    {
 114      bool result = base.IsMatch(name);
 115
 116      if (result) {
 117        var fileInfo = new FileInfo(name);
 118        result =
 119          (MinSize <= fileInfo.Length) &&
 120          (MaxSize >= fileInfo.Length) &&
 121          (MinDate <= fileInfo.LastWriteTime) &&
 122          (MaxDate >= fileInfo.LastWriteTime)
 123          ;
 124      }
 125      return result;
 126    }
 127    #endregion
 128
 129    #region Properties
 130    /// <summary>
 131    /// Get/set the minimum size/length for a file that will match this filter.
 132    /// </summary>
 133    /// <remarks>The default value is zero.</remarks>
 134    /// <exception cref="ArgumentOutOfRangeException">value is less than zero; greater than <see cref="MaxSize"/></excep
 135    public long MinSize {
 136      get { return minSize_; }
 137      set {
 138        if ((value < 0) || (maxSize_ < value)) {
 139          throw new ArgumentOutOfRangeException(nameof(value));
 140        }
 141
 142        minSize_ = value;
 143      }
 144    }
 145
 146    /// <summary>
 147    /// Get/set the maximum size/length for a file that will match this filter.
 148    /// </summary>
 149    /// <remarks>The default value is <see cref="System.Int64.MaxValue"/></remarks>
 150    /// <exception cref="ArgumentOutOfRangeException">value is less than zero or less than <see cref="MinSize"/></except
 151    public long MaxSize {
 152      get { return maxSize_; }
 153      set {
 154        if ((value < 0) || (minSize_ > value)) {
 155          throw new ArgumentOutOfRangeException(nameof(value));
 156        }
 157
 158        maxSize_ = value;
 159      }
 160    }
 161
 162    /// <summary>
 163    /// Get/set the minimum <see cref="DateTime"/> value that will match for this filter.
 164    /// </summary>
 165    /// <remarks>Files with a LastWrite time less than this value are excluded by the filter.</remarks>
 166    public DateTime MinDate {
 167      get {
 168        return minDate_;
 169      }
 170
 171      set {
 172        if (value > maxDate_) {
 173          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MaxDate");
 174        }
 175
 176        minDate_ = value;
 177      }
 178    }
 179
 180    /// <summary>
 181    /// Get/set the maximum <see cref="DateTime"/> value that will match for this filter.
 182    /// </summary>
 183    /// <remarks>Files with a LastWrite time greater than this value are excluded by the filter.</remarks>
 184    public DateTime MaxDate {
 185      get {
 186        return maxDate_;
 187      }
 188
 189      set {
 190        if (minDate_ > value) {
 191          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MinDate");
 192        }
 193
 194        maxDate_ = value;
 195      }
 196    }
 197    #endregion
 198
 199    #region Instance Fields
 200    long minSize_;
 201    long maxSize_ = long.MaxValue;
 202    DateTime minDate_ = DateTime.MinValue;
 203    DateTime maxDate_ = DateTime.MaxValue;
 204    #endregion
 205  }
 206
 207  /// <summary>
 208  /// NameAndSizeFilter filters based on name and file size.
 209  /// </summary>
 210  /// <remarks>A sample showing how filters might be extended.</remarks>
 211  [Obsolete("Use ExtendedPathFilter instead")]
 212  public class NameAndSizeFilter : PathFilter
 213  {
 214
 215    /// <summary>
 216    /// Initialise a new instance of NameAndSizeFilter.
 217    /// </summary>
 218    /// <param name="filter">The filter to apply.</param>
 219    /// <param name="minSize">The minimum file size to include.</param>
 220    /// <param name="maxSize">The maximum file size to include.</param>
 221    public NameAndSizeFilter(string filter, long minSize, long maxSize)
 222      : base(filter)
 223    {
 224      MinSize = minSize;
 225      MaxSize = maxSize;
 226    }
 227
 228    /// <summary>
 229    /// Test a filename to see if it matches the filter.
 230    /// </summary>
 231    /// <param name="name">The filename to test.</param>
 232    /// <returns>True if the filter matches, false otherwise.</returns>
 233    public override bool IsMatch(string name)
 234    {
 235      bool result = base.IsMatch(name);
 236
 237      if (result) {
 238        var fileInfo = new FileInfo(name);
 239        long length = fileInfo.Length;
 240        result =
 241          (MinSize <= length) &&
 242          (MaxSize >= length);
 243      }
 244      return result;
 245    }
 246
 247    /// <summary>
 248    /// Get/set the minimum size for a file that will match this filter.
 249    /// </summary>
 250    public long MinSize {
 251      get { return minSize_; }
 252      set {
 253        if ((value < 0) || (maxSize_ < value)) {
 254          throw new ArgumentOutOfRangeException(nameof(value));
 255        }
 256
 257        minSize_ = value;
 258      }
 259    }
 260
 261    /// <summary>
 262    /// Get/set the maximum size for a file that will match this filter.
 263    /// </summary>
 264    public long MaxSize {
 265      get { return maxSize_; }
 266      set {
 267        if ((value < 0) || (minSize_ > value)) {
 268          throw new ArgumentOutOfRangeException(nameof(value));
 269        }
 270
 271        maxSize_ = value;
 272      }
 273    }
 274
 275    #region Instance Fields
 276    long minSize_;
 277    long maxSize_ = long.MaxValue;
 278    #endregion
 279  }
 280}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_PendingBuffer.htm b/docs/opencover/ICSharpCode.SharpZipLib_PendingBuffer.htm new file mode 100644 index 000000000..44fe308b7 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_PendingBuffer.htm @@ -0,0 +1,308 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\PendingBuffer.cs
Covered lines:40
Uncovered lines:18
Coverable lines:58
Total lines:255
Line coverage:68.9%
Branch coverage:90%
+

Metrics

+ + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()100
.ctor(...)1100100
Reset()1100100
WriteByte(...)100
WriteShort(...)1100100
WriteInt(...)100
WriteBlock(...)1100100
AlignToByte()3100100
WriteBits(...)2100100
WriteShortMSB(...)1100100
Flush(...)376.9280
ToByteArray()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\PendingBuffer.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Zip.Compression
 4{
 5  /// <summary>
 6  /// This class is general purpose class for writing data to a buffer.
 7  ///
 8  /// It allows you to write bits as well as bytes
 9  /// Based on DeflaterPending.java
 10  ///
 11  /// author of the original java version : Jochen Hoenicke
 12  /// </summary>
 13  public class PendingBuffer
 14  {
 15    readonly
 16    #region Instance Fields
 17    /// <summary>
 18    /// Internal work buffer
 19    /// </summary>
 20    byte[] buffer_;
 21
 22    int start;
 23    int end;
 24
 25    uint bits;
 26    int bitCount;
 27    #endregion
 28
 29    #region Constructors
 30    /// <summary>
 31    /// construct instance using default buffer size of 4096
 32    /// </summary>
 033    public PendingBuffer() : this(4096)
 34    {
 035    }
 36
 37    /// <summary>
 38    /// construct instance using specified buffer size
 39    /// </summary>
 40    /// <param name="bufferSize">
 41    /// size to use for internal buffer
 42    /// </param>
 27343    public PendingBuffer(int bufferSize)
 44    {
 27345      buffer_ = new byte[bufferSize];
 27346    }
 47
 48    #endregion
 49
 50    /// <summary>
 51    /// Clear internal state/buffers
 52    /// </summary>
 53    public void Reset()
 54    {
 39255      start = end = bitCount = 0;
 39256    }
 57
 58    /// <summary>
 59    /// Write a byte to buffer
 60    /// </summary>
 61    /// <param name="value">
 62    /// The value to write
 63    /// </param>
 64    public void WriteByte(int value)
 65    {
 66#if DebugDeflation
 67      if (DeflaterConstants.DEBUGGING && (start != 0) )
 68      {
 69        throw new SharpZipBaseException("Debug check: start != 0");
 70      }
 71#endif
 072      buffer_[end++] = unchecked((byte)value);
 073    }
 74
 75    /// <summary>
 76    /// Write a short value to buffer LSB first
 77    /// </summary>
 78    /// <param name="value">
 79    /// The value to write.
 80    /// </param>
 81    public void WriteShort(int value)
 82    {
 83#if DebugDeflation
 84      if (DeflaterConstants.DEBUGGING && (start != 0) )
 85      {
 86        throw new SharpZipBaseException("Debug check: start != 0");
 87      }
 88#endif
 58689      buffer_[end++] = unchecked((byte)value);
 58690      buffer_[end++] = unchecked((byte)(value >> 8));
 58691    }
 92
 93    /// <summary>
 94    /// write an integer LSB first
 95    /// </summary>
 96    /// <param name="value">The value to write.</param>
 97    public void WriteInt(int value)
 98    {
 99#if DebugDeflation
 100      if (DeflaterConstants.DEBUGGING && (start != 0) )
 101      {
 102        throw new SharpZipBaseException("Debug check: start != 0");
 103      }
 104#endif
 0105      buffer_[end++] = unchecked((byte)value);
 0106      buffer_[end++] = unchecked((byte)(value >> 8));
 0107      buffer_[end++] = unchecked((byte)(value >> 16));
 0108      buffer_[end++] = unchecked((byte)(value >> 24));
 0109    }
 110
 111    /// <summary>
 112    /// Write a block of data to buffer
 113    /// </summary>
 114    /// <param name="block">data to write</param>
 115    /// <param name="offset">offset of first byte to write</param>
 116    /// <param name="length">number of bytes to write</param>
 117    public void WriteBlock(byte[] block, int offset, int length)
 118    {
 119#if DebugDeflation
 120      if (DeflaterConstants.DEBUGGING && (start != 0) )
 121      {
 122        throw new SharpZipBaseException("Debug check: start != 0");
 123      }
 124#endif
 293125      System.Array.Copy(block, offset, buffer_, end, length);
 293126      end += length;
 293127    }
 128
 129    /// <summary>
 130    /// The number of bits written to the buffer
 131    /// </summary>
 132    public int BitCount {
 133      get {
 0134        return bitCount;
 135      }
 136    }
 137
 138    /// <summary>
 139    /// Align internal buffer on a byte boundary
 140    /// </summary>
 141    public void AlignToByte()
 142    {
 143#if DebugDeflation
 144      if (DeflaterConstants.DEBUGGING && (start != 0) )
 145      {
 146        throw new SharpZipBaseException("Debug check: start != 0");
 147      }
 148#endif
 598149       if (bitCount > 0) {
 531150        buffer_[end++] = unchecked((byte)bits);
 531151         if (bitCount > 8) {
 174152          buffer_[end++] = unchecked((byte)(bits >> 8));
 153        }
 154      }
 598155      bits = 0;
 598156      bitCount = 0;
 598157    }
 158
 159    /// <summary>
 160    /// Write bits to internal buffer
 161    /// </summary>
 162    /// <param name="b">source of bits</param>
 163    /// <param name="count">number of bits to write</param>
 164    public void WriteBits(int b, int count)
 165    {
 166#if DebugDeflation
 167      if (DeflaterConstants.DEBUGGING && (start != 0) )
 168      {
 169        throw new SharpZipBaseException("Debug check: start != 0");
 170      }
 171
 172      //      if (DeflaterConstants.DEBUGGING) {
 173      //        //Console.WriteLine("writeBits("+b+","+count+")");
 174      //      }
 175#endif
 8954176      bits |= (uint)(b << bitCount);
 8954177      bitCount += count;
 8954178       if (bitCount >= 16) {
 4181179        buffer_[end++] = unchecked((byte)bits);
 4181180        buffer_[end++] = unchecked((byte)(bits >> 8));
 4181181        bits >>= 16;
 4181182        bitCount -= 16;
 183      }
 8954184    }
 185
 186    /// <summary>
 187    /// Write a short value to internal buffer most significant byte first
 188    /// </summary>
 189    /// <param name="s">value to write</param>
 190    public void WriteShortMSB(int s)
 191    {
 192#if DebugDeflation
 193      if (DeflaterConstants.DEBUGGING && (start != 0) )
 194      {
 195        throw new SharpZipBaseException("Debug check: start != 0");
 196      }
 197#endif
 42198      buffer_[end++] = unchecked((byte)(s >> 8));
 42199      buffer_[end++] = unchecked((byte)s);
 42200    }
 201
 202    /// <summary>
 203    /// Indicates if buffer has been flushed
 204    /// </summary>
 205    public bool IsFlushed {
 206      get {
 10175207        return end == 0;
 208      }
 209    }
 210
 211    /// <summary>
 212    /// Flushes the pending buffer into the given output array.  If the
 213    /// output array is to small, only a partial flush is done.
 214    /// </summary>
 215    /// <param name="output">The output array.</param>
 216    /// <param name="offset">The offset into output array.</param>
 217    /// <param name="length">The maximum number of bytes to store.</param>
 218    /// <returns>The number of bytes flushed.</returns>
 219    public int Flush(byte[] output, int offset, int length)
 220    {
 13248221       if (bitCount >= 8) {
 0222        buffer_[end++] = unchecked((byte)bits);
 0223        bits >>= 8;
 0224        bitCount -= 8;
 225      }
 226
 13248227       if (length > end - start) {
 5183228        length = end - start;
 5183229        System.Array.Copy(buffer_, start, output, offset, length);
 5183230        start = 0;
 5183231        end = 0;
 5183232      } else {
 8065233        System.Array.Copy(buffer_, start, output, offset, length);
 8065234        start += length;
 235      }
 13248236      return length;
 237    }
 238
 239    /// <summary>
 240    /// Convert internal buffer to byte array.
 241    /// Buffer is empty on completion
 242    /// </summary>
 243    /// <returns>
 244    /// The internal buffer contents converted to a byte array.
 245    /// </returns>
 246    public byte[] ToByteArray()
 247    {
 0248      byte[] result = new byte[end - start];
 0249      System.Array.Copy(buffer_, start, result, 0, result.Length);
 0250      start = 0;
 0251      end = 0;
 0252      return result;
 253    }
 254  }
 255}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassic.htm b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassic.htm new file mode 100644 index 000000000..cccf63232 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassic.htm @@ -0,0 +1,487 @@ + + + + +ICSharpCode.SharpZipLib.Encryption.PkzipClassic - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Encryption.PkzipClassic
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs
Covered lines:26
Uncovered lines:2
Coverable lines:28
Total lines:445
Line coverage:92.8%
Branch coverage:66.6%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
GenerateKeys(...)492.3171.43
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3using ICSharpCode.SharpZipLib.Checksum;
 4
 5namespace ICSharpCode.SharpZipLib.Encryption
 6{
 7  /// <summary>
 8  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.
 9  /// While it has been superceded by more recent and more powerful algorithms, its still in use and
 10  /// is viable for preventing casual snooping
 11  /// </summary>
 12  public abstract class PkzipClassic : SymmetricAlgorithm
 13  {
 14    /// <summary>
 15    /// Generates new encryption keys based on given seed
 16    /// </summary>
 17    /// <param name="seed">The seed value to initialise keys with.</param>
 18    /// <returns>A new key value.</returns>
 19    static public byte[] GenerateKeys(byte[] seed)
 20    {
 6821       if (seed == null) {
 022        throw new ArgumentNullException(nameof(seed));
 23      }
 24
 6825       if (seed.Length == 0) {
 026        throw new ArgumentException("Length is zero", nameof(seed));
 27      }
 28
 6829      uint[] newKeys = {
 6830        0x12345678,
 6831        0x23456789,
 6832        0x34567890
 6833       };
 34
 103435       for (int i = 0; i < seed.Length; ++i) {
 44936        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);
 44937        newKeys[1] = newKeys[1] + (byte)newKeys[0];
 44938        newKeys[1] = newKeys[1] * 134775813 + 1;
 44939        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));
 40      }
 41
 6842      byte[] result = new byte[12];
 6843      result[0] = (byte)(newKeys[0] & 0xff);
 6844      result[1] = (byte)((newKeys[0] >> 8) & 0xff);
 6845      result[2] = (byte)((newKeys[0] >> 16) & 0xff);
 6846      result[3] = (byte)((newKeys[0] >> 24) & 0xff);
 6847      result[4] = (byte)(newKeys[1] & 0xff);
 6848      result[5] = (byte)((newKeys[1] >> 8) & 0xff);
 6849      result[6] = (byte)((newKeys[1] >> 16) & 0xff);
 6850      result[7] = (byte)((newKeys[1] >> 24) & 0xff);
 6851      result[8] = (byte)(newKeys[2] & 0xff);
 6852      result[9] = (byte)((newKeys[2] >> 8) & 0xff);
 6853      result[10] = (byte)((newKeys[2] >> 16) & 0xff);
 6854      result[11] = (byte)((newKeys[2] >> 24) & 0xff);
 6855      return result;
 56    }
 57  }
 58
 59  /// <summary>
 60  /// PkzipClassicCryptoBase provides the low level facilities for encryption
 61  /// and decryption using the PkzipClassic algorithm.
 62  /// </summary>
 63  class PkzipClassicCryptoBase
 64  {
 65    /// <summary>
 66    /// Transform a single byte
 67    /// </summary>
 68    /// <returns>
 69    /// The transformed value
 70    /// </returns>
 71    protected byte TransformByte()
 72    {
 73      uint temp = ((keys[2] & 0xFFFF) | 2);
 74      return (byte)((temp * (temp ^ 1)) >> 8);
 75    }
 76
 77    /// <summary>
 78    /// Set the key schedule for encryption/decryption.
 79    /// </summary>
 80    /// <param name="keyData">The data use to set the keys from.</param>
 81    protected void SetKeys(byte[] keyData)
 82    {
 83      if (keyData == null) {
 84        throw new ArgumentNullException(nameof(keyData));
 85      }
 86
 87      if (keyData.Length != 12) {
 88        throw new InvalidOperationException("Key length is not valid");
 89      }
 90
 91      keys = new uint[3];
 92      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);
 93      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);
 94      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);
 95    }
 96
 97    /// <summary>
 98    /// Update encryption keys
 99    /// </summary>
 100    protected void UpdateKeys(byte ch)
 101    {
 102      keys[0] = Crc32.ComputeCrc32(keys[0], ch);
 103      keys[1] = keys[1] + (byte)keys[0];
 104      keys[1] = keys[1] * 134775813 + 1;
 105      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
 106    }
 107
 108    /// <summary>
 109    /// Reset the internal state.
 110    /// </summary>
 111    protected void Reset()
 112    {
 113      keys[0] = 0;
 114      keys[1] = 0;
 115      keys[2] = 0;
 116    }
 117
 118    #region Instance Fields
 119    uint[] keys;
 120    #endregion
 121  }
 122
 123  /// <summary>
 124  /// PkzipClassic CryptoTransform for encryption.
 125  /// </summary>
 126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 127  {
 128    /// <summary>
 129    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>
 130    /// </summary>
 131    /// <param name="keyBlock">The key block to use.</param>
 132    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)
 133    {
 134      SetKeys(keyBlock);
 135    }
 136
 137    #region ICryptoTransform Members
 138
 139    /// <summary>
 140    /// Transforms the specified region of the specified byte array.
 141    /// </summary>
 142    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 143    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 144    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 145    /// <returns>The computed transform.</returns>
 146    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 147    {
 148      byte[] result = new byte[inputCount];
 149      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 150      return result;
 151    }
 152
 153    /// <summary>
 154    /// Transforms the specified region of the input byte array and copies
 155    /// the resulting transform to the specified region of the output byte array.
 156    /// </summary>
 157    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 158    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 159    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 160    /// <param name="outputBuffer">The output to which to write the transform.</param>
 161    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 162    /// <returns>The number of bytes written.</returns>
 163    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 164    {
 165      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 166        byte oldbyte = inputBuffer[i];
 167        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());
 168        UpdateKeys(oldbyte);
 169      }
 170      return inputCount;
 171    }
 172
 173    /// <summary>
 174    /// Gets a value indicating whether the current transform can be reused.
 175    /// </summary>
 176    public bool CanReuseTransform {
 177      get {
 178        return true;
 179      }
 180    }
 181
 182    /// <summary>
 183    /// Gets the size of the input data blocks in bytes.
 184    /// </summary>
 185    public int InputBlockSize {
 186      get {
 187        return 1;
 188      }
 189    }
 190
 191    /// <summary>
 192    /// Gets the size of the output data blocks in bytes.
 193    /// </summary>
 194    public int OutputBlockSize {
 195      get {
 196        return 1;
 197      }
 198    }
 199
 200    /// <summary>
 201    /// Gets a value indicating whether multiple blocks can be transformed.
 202    /// </summary>
 203    public bool CanTransformMultipleBlocks {
 204      get {
 205        return true;
 206      }
 207    }
 208
 209    #endregion
 210
 211    #region IDisposable Members
 212
 213    /// <summary>
 214    /// Cleanup internal state.
 215    /// </summary>
 216    public void Dispose()
 217    {
 218      Reset();
 219    }
 220
 221    #endregion
 222  }
 223
 224
 225  /// <summary>
 226  /// PkzipClassic CryptoTransform for decryption.
 227  /// </summary>
 228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 229  {
 230    /// <summary>
 231    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.
 232    /// </summary>
 233    /// <param name="keyBlock">The key block to decrypt with.</param>
 234    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)
 235    {
 236      SetKeys(keyBlock);
 237    }
 238
 239    #region ICryptoTransform Members
 240
 241    /// <summary>
 242    /// Transforms the specified region of the specified byte array.
 243    /// </summary>
 244    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 245    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 246    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 247    /// <returns>The computed transform.</returns>
 248    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 249    {
 250      byte[] result = new byte[inputCount];
 251      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 252      return result;
 253    }
 254
 255    /// <summary>
 256    /// Transforms the specified region of the input byte array and copies
 257    /// the resulting transform to the specified region of the output byte array.
 258    /// </summary>
 259    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 260    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 261    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 262    /// <param name="outputBuffer">The output to which to write the transform.</param>
 263    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 264    /// <returns>The number of bytes written.</returns>
 265    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 266    {
 267      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 268        var newByte = (byte)(inputBuffer[i] ^ TransformByte());
 269        outputBuffer[outputOffset++] = newByte;
 270        UpdateKeys(newByte);
 271      }
 272      return inputCount;
 273    }
 274
 275    /// <summary>
 276    /// Gets a value indicating whether the current transform can be reused.
 277    /// </summary>
 278    public bool CanReuseTransform {
 279      get {
 280        return true;
 281      }
 282    }
 283
 284    /// <summary>
 285    /// Gets the size of the input data blocks in bytes.
 286    /// </summary>
 287    public int InputBlockSize {
 288      get {
 289        return 1;
 290      }
 291    }
 292
 293    /// <summary>
 294    /// Gets the size of the output data blocks in bytes.
 295    /// </summary>
 296    public int OutputBlockSize {
 297      get {
 298        return 1;
 299      }
 300    }
 301
 302    /// <summary>
 303    /// Gets a value indicating whether multiple blocks can be transformed.
 304    /// </summary>
 305    public bool CanTransformMultipleBlocks {
 306      get {
 307        return true;
 308      }
 309    }
 310
 311    #endregion
 312
 313    #region IDisposable Members
 314
 315    /// <summary>
 316    /// Cleanup internal state.
 317    /// </summary>
 318    public void Dispose()
 319    {
 320      Reset();
 321    }
 322
 323    #endregion
 324  }
 325
 326  /// <summary>
 327  /// Defines a wrapper object to access the Pkzip algorithm.
 328  /// This class cannot be inherited.
 329  /// </summary>
 330  public sealed class PkzipClassicManaged : PkzipClassic
 331  {
 332    /// <summary>
 333    /// Get / set the applicable block size in bits.
 334    /// </summary>
 335    /// <remarks>The only valid block size is 8.</remarks>
 336    public override int BlockSize {
 337      get {
 338        return 8;
 339      }
 340
 341      set {
 342        if (value != 8) {
 343          throw new CryptographicException("Block size is invalid");
 344        }
 345      }
 346    }
 347
 348    /// <summary>
 349    /// Get an array of legal <see cref="KeySizes">key sizes.</see>
 350    /// </summary>
 351    public override KeySizes[] LegalKeySizes {
 352      get {
 353        KeySizes[] keySizes = new KeySizes[1];
 354        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);
 355        return keySizes;
 356      }
 357    }
 358
 359    /// <summary>
 360    /// Generate an initial vector.
 361    /// </summary>
 362    public override void GenerateIV()
 363    {
 364      // Do nothing.
 365    }
 366
 367    /// <summary>
 368    /// Get an array of legal <see cref="KeySizes">block sizes</see>.
 369    /// </summary>
 370    public override KeySizes[] LegalBlockSizes {
 371      get {
 372        KeySizes[] keySizes = new KeySizes[1];
 373        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);
 374        return keySizes;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Get / set the key value applicable.
 380    /// </summary>
 381    public override byte[] Key {
 382      get {
 383        if (key_ == null) {
 384          GenerateKey();
 385        }
 386
 387        return (byte[])key_.Clone();
 388      }
 389
 390      set {
 391        if (value == null) {
 392          throw new ArgumentNullException(nameof(value));
 393        }
 394
 395        if (value.Length != 12) {
 396          throw new CryptographicException("Key size is illegal");
 397        }
 398
 399        key_ = (byte[])value.Clone();
 400      }
 401    }
 402
 403    /// <summary>
 404    /// Generate a new random key.
 405    /// </summary>
 406    public override void GenerateKey()
 407    {
 408      key_ = new byte[12];
 409      var rnd = new Random();
 410      rnd.NextBytes(key_);
 411    }
 412
 413    /// <summary>
 414    /// Create an encryptor.
 415    /// </summary>
 416    /// <param name="rgbKey">The key to use for this encryptor.</param>
 417    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>
 418    /// <returns>Returns a new PkzipClassic encryptor</returns>
 419    public override ICryptoTransform CreateEncryptor(
 420      byte[] rgbKey,
 421      byte[] rgbIV)
 422    {
 423      key_ = rgbKey;
 424      return new PkzipClassicEncryptCryptoTransform(Key);
 425    }
 426
 427    /// <summary>
 428    /// Create a decryptor.
 429    /// </summary>
 430    /// <param name="rgbKey">Keys to use for this new decryptor.</param>
 431    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>
 432    /// <returns>Returns a new decryptor.</returns>
 433    public override ICryptoTransform CreateDecryptor(
 434      byte[] rgbKey,
 435      byte[] rgbIV)
 436    {
 437      key_ = rgbKey;
 438      return new PkzipClassicDecryptCryptoTransform(Key);
 439    }
 440
 441    #region Instance Fields
 442    byte[] key_;
 443    #endregion
 444  }
 445}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicCryptoBase.htm b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicCryptoBase.htm new file mode 100644 index 000000000..b846bbe8d --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicCryptoBase.htm @@ -0,0 +1,490 @@ + + + + +ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs
Covered lines:18
Uncovered lines:2
Coverable lines:20
Total lines:445
Line coverage:90%
Branch coverage:50%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
TransformByte()1100100
SetKeys(...)377.7860
UpdateKeys(...)1100100
Reset()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3using ICSharpCode.SharpZipLib.Checksum;
 4
 5namespace ICSharpCode.SharpZipLib.Encryption
 6{
 7  /// <summary>
 8  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.
 9  /// While it has been superceded by more recent and more powerful algorithms, its still in use and
 10  /// is viable for preventing casual snooping
 11  /// </summary>
 12  public abstract class PkzipClassic : SymmetricAlgorithm
 13  {
 14    /// <summary>
 15    /// Generates new encryption keys based on given seed
 16    /// </summary>
 17    /// <param name="seed">The seed value to initialise keys with.</param>
 18    /// <returns>A new key value.</returns>
 19    static public byte[] GenerateKeys(byte[] seed)
 20    {
 21      if (seed == null) {
 22        throw new ArgumentNullException(nameof(seed));
 23      }
 24
 25      if (seed.Length == 0) {
 26        throw new ArgumentException("Length is zero", nameof(seed));
 27      }
 28
 29      uint[] newKeys = {
 30        0x12345678,
 31        0x23456789,
 32        0x34567890
 33       };
 34
 35      for (int i = 0; i < seed.Length; ++i) {
 36        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);
 37        newKeys[1] = newKeys[1] + (byte)newKeys[0];
 38        newKeys[1] = newKeys[1] * 134775813 + 1;
 39        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));
 40      }
 41
 42      byte[] result = new byte[12];
 43      result[0] = (byte)(newKeys[0] & 0xff);
 44      result[1] = (byte)((newKeys[0] >> 8) & 0xff);
 45      result[2] = (byte)((newKeys[0] >> 16) & 0xff);
 46      result[3] = (byte)((newKeys[0] >> 24) & 0xff);
 47      result[4] = (byte)(newKeys[1] & 0xff);
 48      result[5] = (byte)((newKeys[1] >> 8) & 0xff);
 49      result[6] = (byte)((newKeys[1] >> 16) & 0xff);
 50      result[7] = (byte)((newKeys[1] >> 24) & 0xff);
 51      result[8] = (byte)(newKeys[2] & 0xff);
 52      result[9] = (byte)((newKeys[2] >> 8) & 0xff);
 53      result[10] = (byte)((newKeys[2] >> 16) & 0xff);
 54      result[11] = (byte)((newKeys[2] >> 24) & 0xff);
 55      return result;
 56    }
 57  }
 58
 59  /// <summary>
 60  /// PkzipClassicCryptoBase provides the low level facilities for encryption
 61  /// and decryption using the PkzipClassic algorithm.
 62  /// </summary>
 63  class PkzipClassicCryptoBase
 64  {
 65    /// <summary>
 66    /// Transform a single byte
 67    /// </summary>
 68    /// <returns>
 69    /// The transformed value
 70    /// </returns>
 71    protected byte TransformByte()
 72    {
 225787273      uint temp = ((keys[2] & 0xFFFF) | 2);
 225787274      return (byte)((temp * (temp ^ 1)) >> 8);
 75    }
 76
 77    /// <summary>
 78    /// Set the key schedule for encryption/decryption.
 79    /// </summary>
 80    /// <param name="keyData">The data use to set the keys from.</param>
 81    protected void SetKeys(byte[] keyData)
 82    {
 7283       if (keyData == null) {
 084        throw new ArgumentNullException(nameof(keyData));
 85      }
 86
 7287       if (keyData.Length != 12) {
 088        throw new InvalidOperationException("Key length is not valid");
 89      }
 90
 7291      keys = new uint[3];
 7292      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);
 7293      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);
 7294      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);
 7295    }
 96
 97    /// <summary>
 98    /// Update encryption keys
 99    /// </summary>
 100    protected void UpdateKeys(byte ch)
 101    {
 2257872102      keys[0] = Crc32.ComputeCrc32(keys[0], ch);
 2257872103      keys[1] = keys[1] + (byte)keys[0];
 2257872104      keys[1] = keys[1] * 134775813 + 1;
 2257872105      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
 2257872106    }
 107
 108    /// <summary>
 109    /// Reset the internal state.
 110    /// </summary>
 111    protected void Reset()
 112    {
 32113      keys[0] = 0;
 32114      keys[1] = 0;
 32115      keys[2] = 0;
 32116    }
 117
 118    #region Instance Fields
 119    uint[] keys;
 120    #endregion
 121  }
 122
 123  /// <summary>
 124  /// PkzipClassic CryptoTransform for encryption.
 125  /// </summary>
 126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 127  {
 128    /// <summary>
 129    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>
 130    /// </summary>
 131    /// <param name="keyBlock">The key block to use.</param>
 132    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)
 133    {
 134      SetKeys(keyBlock);
 135    }
 136
 137    #region ICryptoTransform Members
 138
 139    /// <summary>
 140    /// Transforms the specified region of the specified byte array.
 141    /// </summary>
 142    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 143    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 144    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 145    /// <returns>The computed transform.</returns>
 146    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 147    {
 148      byte[] result = new byte[inputCount];
 149      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 150      return result;
 151    }
 152
 153    /// <summary>
 154    /// Transforms the specified region of the input byte array and copies
 155    /// the resulting transform to the specified region of the output byte array.
 156    /// </summary>
 157    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 158    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 159    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 160    /// <param name="outputBuffer">The output to which to write the transform.</param>
 161    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 162    /// <returns>The number of bytes written.</returns>
 163    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 164    {
 165      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 166        byte oldbyte = inputBuffer[i];
 167        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());
 168        UpdateKeys(oldbyte);
 169      }
 170      return inputCount;
 171    }
 172
 173    /// <summary>
 174    /// Gets a value indicating whether the current transform can be reused.
 175    /// </summary>
 176    public bool CanReuseTransform {
 177      get {
 178        return true;
 179      }
 180    }
 181
 182    /// <summary>
 183    /// Gets the size of the input data blocks in bytes.
 184    /// </summary>
 185    public int InputBlockSize {
 186      get {
 187        return 1;
 188      }
 189    }
 190
 191    /// <summary>
 192    /// Gets the size of the output data blocks in bytes.
 193    /// </summary>
 194    public int OutputBlockSize {
 195      get {
 196        return 1;
 197      }
 198    }
 199
 200    /// <summary>
 201    /// Gets a value indicating whether multiple blocks can be transformed.
 202    /// </summary>
 203    public bool CanTransformMultipleBlocks {
 204      get {
 205        return true;
 206      }
 207    }
 208
 209    #endregion
 210
 211    #region IDisposable Members
 212
 213    /// <summary>
 214    /// Cleanup internal state.
 215    /// </summary>
 216    public void Dispose()
 217    {
 218      Reset();
 219    }
 220
 221    #endregion
 222  }
 223
 224
 225  /// <summary>
 226  /// PkzipClassic CryptoTransform for decryption.
 227  /// </summary>
 228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 229  {
 230    /// <summary>
 231    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.
 232    /// </summary>
 233    /// <param name="keyBlock">The key block to decrypt with.</param>
 234    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)
 235    {
 236      SetKeys(keyBlock);
 237    }
 238
 239    #region ICryptoTransform Members
 240
 241    /// <summary>
 242    /// Transforms the specified region of the specified byte array.
 243    /// </summary>
 244    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 245    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 246    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 247    /// <returns>The computed transform.</returns>
 248    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 249    {
 250      byte[] result = new byte[inputCount];
 251      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 252      return result;
 253    }
 254
 255    /// <summary>
 256    /// Transforms the specified region of the input byte array and copies
 257    /// the resulting transform to the specified region of the output byte array.
 258    /// </summary>
 259    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 260    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 261    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 262    /// <param name="outputBuffer">The output to which to write the transform.</param>
 263    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 264    /// <returns>The number of bytes written.</returns>
 265    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 266    {
 267      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 268        var newByte = (byte)(inputBuffer[i] ^ TransformByte());
 269        outputBuffer[outputOffset++] = newByte;
 270        UpdateKeys(newByte);
 271      }
 272      return inputCount;
 273    }
 274
 275    /// <summary>
 276    /// Gets a value indicating whether the current transform can be reused.
 277    /// </summary>
 278    public bool CanReuseTransform {
 279      get {
 280        return true;
 281      }
 282    }
 283
 284    /// <summary>
 285    /// Gets the size of the input data blocks in bytes.
 286    /// </summary>
 287    public int InputBlockSize {
 288      get {
 289        return 1;
 290      }
 291    }
 292
 293    /// <summary>
 294    /// Gets the size of the output data blocks in bytes.
 295    /// </summary>
 296    public int OutputBlockSize {
 297      get {
 298        return 1;
 299      }
 300    }
 301
 302    /// <summary>
 303    /// Gets a value indicating whether multiple blocks can be transformed.
 304    /// </summary>
 305    public bool CanTransformMultipleBlocks {
 306      get {
 307        return true;
 308      }
 309    }
 310
 311    #endregion
 312
 313    #region IDisposable Members
 314
 315    /// <summary>
 316    /// Cleanup internal state.
 317    /// </summary>
 318    public void Dispose()
 319    {
 320      Reset();
 321    }
 322
 323    #endregion
 324  }
 325
 326  /// <summary>
 327  /// Defines a wrapper object to access the Pkzip algorithm.
 328  /// This class cannot be inherited.
 329  /// </summary>
 330  public sealed class PkzipClassicManaged : PkzipClassic
 331  {
 332    /// <summary>
 333    /// Get / set the applicable block size in bits.
 334    /// </summary>
 335    /// <remarks>The only valid block size is 8.</remarks>
 336    public override int BlockSize {
 337      get {
 338        return 8;
 339      }
 340
 341      set {
 342        if (value != 8) {
 343          throw new CryptographicException("Block size is invalid");
 344        }
 345      }
 346    }
 347
 348    /// <summary>
 349    /// Get an array of legal <see cref="KeySizes">key sizes.</see>
 350    /// </summary>
 351    public override KeySizes[] LegalKeySizes {
 352      get {
 353        KeySizes[] keySizes = new KeySizes[1];
 354        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);
 355        return keySizes;
 356      }
 357    }
 358
 359    /// <summary>
 360    /// Generate an initial vector.
 361    /// </summary>
 362    public override void GenerateIV()
 363    {
 364      // Do nothing.
 365    }
 366
 367    /// <summary>
 368    /// Get an array of legal <see cref="KeySizes">block sizes</see>.
 369    /// </summary>
 370    public override KeySizes[] LegalBlockSizes {
 371      get {
 372        KeySizes[] keySizes = new KeySizes[1];
 373        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);
 374        return keySizes;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Get / set the key value applicable.
 380    /// </summary>
 381    public override byte[] Key {
 382      get {
 383        if (key_ == null) {
 384          GenerateKey();
 385        }
 386
 387        return (byte[])key_.Clone();
 388      }
 389
 390      set {
 391        if (value == null) {
 392          throw new ArgumentNullException(nameof(value));
 393        }
 394
 395        if (value.Length != 12) {
 396          throw new CryptographicException("Key size is illegal");
 397        }
 398
 399        key_ = (byte[])value.Clone();
 400      }
 401    }
 402
 403    /// <summary>
 404    /// Generate a new random key.
 405    /// </summary>
 406    public override void GenerateKey()
 407    {
 408      key_ = new byte[12];
 409      var rnd = new Random();
 410      rnd.NextBytes(key_);
 411    }
 412
 413    /// <summary>
 414    /// Create an encryptor.
 415    /// </summary>
 416    /// <param name="rgbKey">The key to use for this encryptor.</param>
 417    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>
 418    /// <returns>Returns a new PkzipClassic encryptor</returns>
 419    public override ICryptoTransform CreateEncryptor(
 420      byte[] rgbKey,
 421      byte[] rgbIV)
 422    {
 423      key_ = rgbKey;
 424      return new PkzipClassicEncryptCryptoTransform(Key);
 425    }
 426
 427    /// <summary>
 428    /// Create a decryptor.
 429    /// </summary>
 430    /// <param name="rgbKey">Keys to use for this new decryptor.</param>
 431    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>
 432    /// <returns>Returns a new decryptor.</returns>
 433    public override ICryptoTransform CreateDecryptor(
 434      byte[] rgbKey,
 435      byte[] rgbIV)
 436    {
 437      key_ = rgbKey;
 438      return new PkzipClassicDecryptCryptoTransform(Key);
 439    }
 440
 441    #region Instance Fields
 442    byte[] key_;
 443    #endregion
 444  }
 445}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicDecryptCryptoTransform.htm b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicDecryptCryptoTransform.htm new file mode 100644 index 000000000..ef82a6e09 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicDecryptCryptoTransform.htm @@ -0,0 +1,490 @@ + + + + +ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs
Covered lines:14
Uncovered lines:3
Coverable lines:17
Total lines:445
Line coverage:82.3%
Branch coverage:100%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
TransformFinalBlock(...)1100100
TransformBlock(...)2100100
Dispose()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3using ICSharpCode.SharpZipLib.Checksum;
 4
 5namespace ICSharpCode.SharpZipLib.Encryption
 6{
 7  /// <summary>
 8  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.
 9  /// While it has been superceded by more recent and more powerful algorithms, its still in use and
 10  /// is viable for preventing casual snooping
 11  /// </summary>
 12  public abstract class PkzipClassic : SymmetricAlgorithm
 13  {
 14    /// <summary>
 15    /// Generates new encryption keys based on given seed
 16    /// </summary>
 17    /// <param name="seed">The seed value to initialise keys with.</param>
 18    /// <returns>A new key value.</returns>
 19    static public byte[] GenerateKeys(byte[] seed)
 20    {
 21      if (seed == null) {
 22        throw new ArgumentNullException(nameof(seed));
 23      }
 24
 25      if (seed.Length == 0) {
 26        throw new ArgumentException("Length is zero", nameof(seed));
 27      }
 28
 29      uint[] newKeys = {
 30        0x12345678,
 31        0x23456789,
 32        0x34567890
 33       };
 34
 35      for (int i = 0; i < seed.Length; ++i) {
 36        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);
 37        newKeys[1] = newKeys[1] + (byte)newKeys[0];
 38        newKeys[1] = newKeys[1] * 134775813 + 1;
 39        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));
 40      }
 41
 42      byte[] result = new byte[12];
 43      result[0] = (byte)(newKeys[0] & 0xff);
 44      result[1] = (byte)((newKeys[0] >> 8) & 0xff);
 45      result[2] = (byte)((newKeys[0] >> 16) & 0xff);
 46      result[3] = (byte)((newKeys[0] >> 24) & 0xff);
 47      result[4] = (byte)(newKeys[1] & 0xff);
 48      result[5] = (byte)((newKeys[1] >> 8) & 0xff);
 49      result[6] = (byte)((newKeys[1] >> 16) & 0xff);
 50      result[7] = (byte)((newKeys[1] >> 24) & 0xff);
 51      result[8] = (byte)(newKeys[2] & 0xff);
 52      result[9] = (byte)((newKeys[2] >> 8) & 0xff);
 53      result[10] = (byte)((newKeys[2] >> 16) & 0xff);
 54      result[11] = (byte)((newKeys[2] >> 24) & 0xff);
 55      return result;
 56    }
 57  }
 58
 59  /// <summary>
 60  /// PkzipClassicCryptoBase provides the low level facilities for encryption
 61  /// and decryption using the PkzipClassic algorithm.
 62  /// </summary>
 63  class PkzipClassicCryptoBase
 64  {
 65    /// <summary>
 66    /// Transform a single byte
 67    /// </summary>
 68    /// <returns>
 69    /// The transformed value
 70    /// </returns>
 71    protected byte TransformByte()
 72    {
 73      uint temp = ((keys[2] & 0xFFFF) | 2);
 74      return (byte)((temp * (temp ^ 1)) >> 8);
 75    }
 76
 77    /// <summary>
 78    /// Set the key schedule for encryption/decryption.
 79    /// </summary>
 80    /// <param name="keyData">The data use to set the keys from.</param>
 81    protected void SetKeys(byte[] keyData)
 82    {
 83      if (keyData == null) {
 84        throw new ArgumentNullException(nameof(keyData));
 85      }
 86
 87      if (keyData.Length != 12) {
 88        throw new InvalidOperationException("Key length is not valid");
 89      }
 90
 91      keys = new uint[3];
 92      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);
 93      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);
 94      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);
 95    }
 96
 97    /// <summary>
 98    /// Update encryption keys
 99    /// </summary>
 100    protected void UpdateKeys(byte ch)
 101    {
 102      keys[0] = Crc32.ComputeCrc32(keys[0], ch);
 103      keys[1] = keys[1] + (byte)keys[0];
 104      keys[1] = keys[1] * 134775813 + 1;
 105      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
 106    }
 107
 108    /// <summary>
 109    /// Reset the internal state.
 110    /// </summary>
 111    protected void Reset()
 112    {
 113      keys[0] = 0;
 114      keys[1] = 0;
 115      keys[2] = 0;
 116    }
 117
 118    #region Instance Fields
 119    uint[] keys;
 120    #endregion
 121  }
 122
 123  /// <summary>
 124  /// PkzipClassic CryptoTransform for encryption.
 125  /// </summary>
 126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 127  {
 128    /// <summary>
 129    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>
 130    /// </summary>
 131    /// <param name="keyBlock">The key block to use.</param>
 132    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)
 133    {
 134      SetKeys(keyBlock);
 135    }
 136
 137    #region ICryptoTransform Members
 138
 139    /// <summary>
 140    /// Transforms the specified region of the specified byte array.
 141    /// </summary>
 142    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 143    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 144    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 145    /// <returns>The computed transform.</returns>
 146    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 147    {
 148      byte[] result = new byte[inputCount];
 149      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 150      return result;
 151    }
 152
 153    /// <summary>
 154    /// Transforms the specified region of the input byte array and copies
 155    /// the resulting transform to the specified region of the output byte array.
 156    /// </summary>
 157    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 158    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 159    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 160    /// <param name="outputBuffer">The output to which to write the transform.</param>
 161    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 162    /// <returns>The number of bytes written.</returns>
 163    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 164    {
 165      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 166        byte oldbyte = inputBuffer[i];
 167        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());
 168        UpdateKeys(oldbyte);
 169      }
 170      return inputCount;
 171    }
 172
 173    /// <summary>
 174    /// Gets a value indicating whether the current transform can be reused.
 175    /// </summary>
 176    public bool CanReuseTransform {
 177      get {
 178        return true;
 179      }
 180    }
 181
 182    /// <summary>
 183    /// Gets the size of the input data blocks in bytes.
 184    /// </summary>
 185    public int InputBlockSize {
 186      get {
 187        return 1;
 188      }
 189    }
 190
 191    /// <summary>
 192    /// Gets the size of the output data blocks in bytes.
 193    /// </summary>
 194    public int OutputBlockSize {
 195      get {
 196        return 1;
 197      }
 198    }
 199
 200    /// <summary>
 201    /// Gets a value indicating whether multiple blocks can be transformed.
 202    /// </summary>
 203    public bool CanTransformMultipleBlocks {
 204      get {
 205        return true;
 206      }
 207    }
 208
 209    #endregion
 210
 211    #region IDisposable Members
 212
 213    /// <summary>
 214    /// Cleanup internal state.
 215    /// </summary>
 216    public void Dispose()
 217    {
 218      Reset();
 219    }
 220
 221    #endregion
 222  }
 223
 224
 225  /// <summary>
 226  /// PkzipClassic CryptoTransform for decryption.
 227  /// </summary>
 228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 229  {
 230    /// <summary>
 231    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.
 232    /// </summary>
 233    /// <param name="keyBlock">The key block to decrypt with.</param>
 34234    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)
 235    {
 34236      SetKeys(keyBlock);
 34237    }
 238
 239    #region ICryptoTransform Members
 240
 241    /// <summary>
 242    /// Transforms the specified region of the specified byte array.
 243    /// </summary>
 244    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 245    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 246    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 247    /// <returns>The computed transform.</returns>
 248    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 249    {
 10250      byte[] result = new byte[inputCount];
 10251      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 10252      return result;
 253    }
 254
 255    /// <summary>
 256    /// Transforms the specified region of the input byte array and copies
 257    /// the resulting transform to the specified region of the output byte array.
 258    /// </summary>
 259    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 260    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 261    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 262    /// <param name="outputBuffer">The output to which to write the transform.</param>
 263    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 264    /// <returns>The number of bytes written.</returns>
 265    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 266    {
 2262036267       for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 1130694268        var newByte = (byte)(inputBuffer[i] ^ TransformByte());
 1130694269        outputBuffer[outputOffset++] = newByte;
 1130694270        UpdateKeys(newByte);
 271      }
 324272      return inputCount;
 273    }
 274
 275    /// <summary>
 276    /// Gets a value indicating whether the current transform can be reused.
 277    /// </summary>
 278    public bool CanReuseTransform {
 279      get {
 0280        return true;
 281      }
 282    }
 283
 284    /// <summary>
 285    /// Gets the size of the input data blocks in bytes.
 286    /// </summary>
 287    public int InputBlockSize {
 288      get {
 10289        return 1;
 290      }
 291    }
 292
 293    /// <summary>
 294    /// Gets the size of the output data blocks in bytes.
 295    /// </summary>
 296    public int OutputBlockSize {
 297      get {
 10298        return 1;
 299      }
 300    }
 301
 302    /// <summary>
 303    /// Gets a value indicating whether multiple blocks can be transformed.
 304    /// </summary>
 305    public bool CanTransformMultipleBlocks {
 306      get {
 26307        return true;
 308      }
 309    }
 310
 311    #endregion
 312
 313    #region IDisposable Members
 314
 315    /// <summary>
 316    /// Cleanup internal state.
 317    /// </summary>
 318    public void Dispose()
 319    {
 0320      Reset();
 0321    }
 322
 323    #endregion
 324  }
 325
 326  /// <summary>
 327  /// Defines a wrapper object to access the Pkzip algorithm.
 328  /// This class cannot be inherited.
 329  /// </summary>
 330  public sealed class PkzipClassicManaged : PkzipClassic
 331  {
 332    /// <summary>
 333    /// Get / set the applicable block size in bits.
 334    /// </summary>
 335    /// <remarks>The only valid block size is 8.</remarks>
 336    public override int BlockSize {
 337      get {
 338        return 8;
 339      }
 340
 341      set {
 342        if (value != 8) {
 343          throw new CryptographicException("Block size is invalid");
 344        }
 345      }
 346    }
 347
 348    /// <summary>
 349    /// Get an array of legal <see cref="KeySizes">key sizes.</see>
 350    /// </summary>
 351    public override KeySizes[] LegalKeySizes {
 352      get {
 353        KeySizes[] keySizes = new KeySizes[1];
 354        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);
 355        return keySizes;
 356      }
 357    }
 358
 359    /// <summary>
 360    /// Generate an initial vector.
 361    /// </summary>
 362    public override void GenerateIV()
 363    {
 364      // Do nothing.
 365    }
 366
 367    /// <summary>
 368    /// Get an array of legal <see cref="KeySizes">block sizes</see>.
 369    /// </summary>
 370    public override KeySizes[] LegalBlockSizes {
 371      get {
 372        KeySizes[] keySizes = new KeySizes[1];
 373        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);
 374        return keySizes;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Get / set the key value applicable.
 380    /// </summary>
 381    public override byte[] Key {
 382      get {
 383        if (key_ == null) {
 384          GenerateKey();
 385        }
 386
 387        return (byte[])key_.Clone();
 388      }
 389
 390      set {
 391        if (value == null) {
 392          throw new ArgumentNullException(nameof(value));
 393        }
 394
 395        if (value.Length != 12) {
 396          throw new CryptographicException("Key size is illegal");
 397        }
 398
 399        key_ = (byte[])value.Clone();
 400      }
 401    }
 402
 403    /// <summary>
 404    /// Generate a new random key.
 405    /// </summary>
 406    public override void GenerateKey()
 407    {
 408      key_ = new byte[12];
 409      var rnd = new Random();
 410      rnd.NextBytes(key_);
 411    }
 412
 413    /// <summary>
 414    /// Create an encryptor.
 415    /// </summary>
 416    /// <param name="rgbKey">The key to use for this encryptor.</param>
 417    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>
 418    /// <returns>Returns a new PkzipClassic encryptor</returns>
 419    public override ICryptoTransform CreateEncryptor(
 420      byte[] rgbKey,
 421      byte[] rgbIV)
 422    {
 423      key_ = rgbKey;
 424      return new PkzipClassicEncryptCryptoTransform(Key);
 425    }
 426
 427    /// <summary>
 428    /// Create a decryptor.
 429    /// </summary>
 430    /// <param name="rgbKey">Keys to use for this new decryptor.</param>
 431    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>
 432    /// <returns>Returns a new decryptor.</returns>
 433    public override ICryptoTransform CreateDecryptor(
 434      byte[] rgbKey,
 435      byte[] rgbIV)
 436    {
 437      key_ = rgbKey;
 438      return new PkzipClassicDecryptCryptoTransform(Key);
 439    }
 440
 441    #region Instance Fields
 442    byte[] key_;
 443    #endregion
 444  }
 445}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicEncryptCryptoTransform.htm b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicEncryptCryptoTransform.htm new file mode 100644 index 000000000..03a234a44 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicEncryptCryptoTransform.htm @@ -0,0 +1,490 @@ + + + + +ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs
Covered lines:13
Uncovered lines:4
Coverable lines:17
Total lines:445
Line coverage:76.4%
Branch coverage:100%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
TransformFinalBlock(...)100
TransformBlock(...)2100100
Dispose()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3using ICSharpCode.SharpZipLib.Checksum;
 4
 5namespace ICSharpCode.SharpZipLib.Encryption
 6{
 7  /// <summary>
 8  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.
 9  /// While it has been superceded by more recent and more powerful algorithms, its still in use and
 10  /// is viable for preventing casual snooping
 11  /// </summary>
 12  public abstract class PkzipClassic : SymmetricAlgorithm
 13  {
 14    /// <summary>
 15    /// Generates new encryption keys based on given seed
 16    /// </summary>
 17    /// <param name="seed">The seed value to initialise keys with.</param>
 18    /// <returns>A new key value.</returns>
 19    static public byte[] GenerateKeys(byte[] seed)
 20    {
 21      if (seed == null) {
 22        throw new ArgumentNullException(nameof(seed));
 23      }
 24
 25      if (seed.Length == 0) {
 26        throw new ArgumentException("Length is zero", nameof(seed));
 27      }
 28
 29      uint[] newKeys = {
 30        0x12345678,
 31        0x23456789,
 32        0x34567890
 33       };
 34
 35      for (int i = 0; i < seed.Length; ++i) {
 36        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);
 37        newKeys[1] = newKeys[1] + (byte)newKeys[0];
 38        newKeys[1] = newKeys[1] * 134775813 + 1;
 39        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));
 40      }
 41
 42      byte[] result = new byte[12];
 43      result[0] = (byte)(newKeys[0] & 0xff);
 44      result[1] = (byte)((newKeys[0] >> 8) & 0xff);
 45      result[2] = (byte)((newKeys[0] >> 16) & 0xff);
 46      result[3] = (byte)((newKeys[0] >> 24) & 0xff);
 47      result[4] = (byte)(newKeys[1] & 0xff);
 48      result[5] = (byte)((newKeys[1] >> 8) & 0xff);
 49      result[6] = (byte)((newKeys[1] >> 16) & 0xff);
 50      result[7] = (byte)((newKeys[1] >> 24) & 0xff);
 51      result[8] = (byte)(newKeys[2] & 0xff);
 52      result[9] = (byte)((newKeys[2] >> 8) & 0xff);
 53      result[10] = (byte)((newKeys[2] >> 16) & 0xff);
 54      result[11] = (byte)((newKeys[2] >> 24) & 0xff);
 55      return result;
 56    }
 57  }
 58
 59  /// <summary>
 60  /// PkzipClassicCryptoBase provides the low level facilities for encryption
 61  /// and decryption using the PkzipClassic algorithm.
 62  /// </summary>
 63  class PkzipClassicCryptoBase
 64  {
 65    /// <summary>
 66    /// Transform a single byte
 67    /// </summary>
 68    /// <returns>
 69    /// The transformed value
 70    /// </returns>
 71    protected byte TransformByte()
 72    {
 73      uint temp = ((keys[2] & 0xFFFF) | 2);
 74      return (byte)((temp * (temp ^ 1)) >> 8);
 75    }
 76
 77    /// <summary>
 78    /// Set the key schedule for encryption/decryption.
 79    /// </summary>
 80    /// <param name="keyData">The data use to set the keys from.</param>
 81    protected void SetKeys(byte[] keyData)
 82    {
 83      if (keyData == null) {
 84        throw new ArgumentNullException(nameof(keyData));
 85      }
 86
 87      if (keyData.Length != 12) {
 88        throw new InvalidOperationException("Key length is not valid");
 89      }
 90
 91      keys = new uint[3];
 92      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);
 93      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);
 94      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);
 95    }
 96
 97    /// <summary>
 98    /// Update encryption keys
 99    /// </summary>
 100    protected void UpdateKeys(byte ch)
 101    {
 102      keys[0] = Crc32.ComputeCrc32(keys[0], ch);
 103      keys[1] = keys[1] + (byte)keys[0];
 104      keys[1] = keys[1] * 134775813 + 1;
 105      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
 106    }
 107
 108    /// <summary>
 109    /// Reset the internal state.
 110    /// </summary>
 111    protected void Reset()
 112    {
 113      keys[0] = 0;
 114      keys[1] = 0;
 115      keys[2] = 0;
 116    }
 117
 118    #region Instance Fields
 119    uint[] keys;
 120    #endregion
 121  }
 122
 123  /// <summary>
 124  /// PkzipClassic CryptoTransform for encryption.
 125  /// </summary>
 126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 127  {
 128    /// <summary>
 129    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>
 130    /// </summary>
 131    /// <param name="keyBlock">The key block to use.</param>
 38132    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)
 133    {
 38134      SetKeys(keyBlock);
 38135    }
 136
 137    #region ICryptoTransform Members
 138
 139    /// <summary>
 140    /// Transforms the specified region of the specified byte array.
 141    /// </summary>
 142    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 143    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 144    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 145    /// <returns>The computed transform.</returns>
 146    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 147    {
 0148      byte[] result = new byte[inputCount];
 0149      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 0150      return result;
 151    }
 152
 153    /// <summary>
 154    /// Transforms the specified region of the input byte array and copies
 155    /// the resulting transform to the specified region of the output byte array.
 156    /// </summary>
 157    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 158    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 159    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 160    /// <param name="outputBuffer">The output to which to write the transform.</param>
 161    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 162    /// <returns>The number of bytes written.</returns>
 163    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 164    {
 2258986165       for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 1127178166        byte oldbyte = inputBuffer[i];
 1127178167        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());
 1127178168        UpdateKeys(oldbyte);
 169      }
 2315170      return inputCount;
 171    }
 172
 173    /// <summary>
 174    /// Gets a value indicating whether the current transform can be reused.
 175    /// </summary>
 176    public bool CanReuseTransform {
 177      get {
 0178        return true;
 179      }
 180    }
 181
 182    /// <summary>
 183    /// Gets the size of the input data blocks in bytes.
 184    /// </summary>
 185    public int InputBlockSize {
 186      get {
 5187        return 1;
 188      }
 189    }
 190
 191    /// <summary>
 192    /// Gets the size of the output data blocks in bytes.
 193    /// </summary>
 194    public int OutputBlockSize {
 195      get {
 5196        return 1;
 197      }
 198    }
 199
 200    /// <summary>
 201    /// Gets a value indicating whether multiple blocks can be transformed.
 202    /// </summary>
 203    public bool CanTransformMultipleBlocks {
 204      get {
 10205        return true;
 206      }
 207    }
 208
 209    #endregion
 210
 211    #region IDisposable Members
 212
 213    /// <summary>
 214    /// Cleanup internal state.
 215    /// </summary>
 216    public void Dispose()
 217    {
 32218      Reset();
 32219    }
 220
 221    #endregion
 222  }
 223
 224
 225  /// <summary>
 226  /// PkzipClassic CryptoTransform for decryption.
 227  /// </summary>
 228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 229  {
 230    /// <summary>
 231    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.
 232    /// </summary>
 233    /// <param name="keyBlock">The key block to decrypt with.</param>
 234    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)
 235    {
 236      SetKeys(keyBlock);
 237    }
 238
 239    #region ICryptoTransform Members
 240
 241    /// <summary>
 242    /// Transforms the specified region of the specified byte array.
 243    /// </summary>
 244    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 245    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 246    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 247    /// <returns>The computed transform.</returns>
 248    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 249    {
 250      byte[] result = new byte[inputCount];
 251      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 252      return result;
 253    }
 254
 255    /// <summary>
 256    /// Transforms the specified region of the input byte array and copies
 257    /// the resulting transform to the specified region of the output byte array.
 258    /// </summary>
 259    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 260    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 261    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 262    /// <param name="outputBuffer">The output to which to write the transform.</param>
 263    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 264    /// <returns>The number of bytes written.</returns>
 265    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 266    {
 267      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 268        var newByte = (byte)(inputBuffer[i] ^ TransformByte());
 269        outputBuffer[outputOffset++] = newByte;
 270        UpdateKeys(newByte);
 271      }
 272      return inputCount;
 273    }
 274
 275    /// <summary>
 276    /// Gets a value indicating whether the current transform can be reused.
 277    /// </summary>
 278    public bool CanReuseTransform {
 279      get {
 280        return true;
 281      }
 282    }
 283
 284    /// <summary>
 285    /// Gets the size of the input data blocks in bytes.
 286    /// </summary>
 287    public int InputBlockSize {
 288      get {
 289        return 1;
 290      }
 291    }
 292
 293    /// <summary>
 294    /// Gets the size of the output data blocks in bytes.
 295    /// </summary>
 296    public int OutputBlockSize {
 297      get {
 298        return 1;
 299      }
 300    }
 301
 302    /// <summary>
 303    /// Gets a value indicating whether multiple blocks can be transformed.
 304    /// </summary>
 305    public bool CanTransformMultipleBlocks {
 306      get {
 307        return true;
 308      }
 309    }
 310
 311    #endregion
 312
 313    #region IDisposable Members
 314
 315    /// <summary>
 316    /// Cleanup internal state.
 317    /// </summary>
 318    public void Dispose()
 319    {
 320      Reset();
 321    }
 322
 323    #endregion
 324  }
 325
 326  /// <summary>
 327  /// Defines a wrapper object to access the Pkzip algorithm.
 328  /// This class cannot be inherited.
 329  /// </summary>
 330  public sealed class PkzipClassicManaged : PkzipClassic
 331  {
 332    /// <summary>
 333    /// Get / set the applicable block size in bits.
 334    /// </summary>
 335    /// <remarks>The only valid block size is 8.</remarks>
 336    public override int BlockSize {
 337      get {
 338        return 8;
 339      }
 340
 341      set {
 342        if (value != 8) {
 343          throw new CryptographicException("Block size is invalid");
 344        }
 345      }
 346    }
 347
 348    /// <summary>
 349    /// Get an array of legal <see cref="KeySizes">key sizes.</see>
 350    /// </summary>
 351    public override KeySizes[] LegalKeySizes {
 352      get {
 353        KeySizes[] keySizes = new KeySizes[1];
 354        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);
 355        return keySizes;
 356      }
 357    }
 358
 359    /// <summary>
 360    /// Generate an initial vector.
 361    /// </summary>
 362    public override void GenerateIV()
 363    {
 364      // Do nothing.
 365    }
 366
 367    /// <summary>
 368    /// Get an array of legal <see cref="KeySizes">block sizes</see>.
 369    /// </summary>
 370    public override KeySizes[] LegalBlockSizes {
 371      get {
 372        KeySizes[] keySizes = new KeySizes[1];
 373        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);
 374        return keySizes;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Get / set the key value applicable.
 380    /// </summary>
 381    public override byte[] Key {
 382      get {
 383        if (key_ == null) {
 384          GenerateKey();
 385        }
 386
 387        return (byte[])key_.Clone();
 388      }
 389
 390      set {
 391        if (value == null) {
 392          throw new ArgumentNullException(nameof(value));
 393        }
 394
 395        if (value.Length != 12) {
 396          throw new CryptographicException("Key size is illegal");
 397        }
 398
 399        key_ = (byte[])value.Clone();
 400      }
 401    }
 402
 403    /// <summary>
 404    /// Generate a new random key.
 405    /// </summary>
 406    public override void GenerateKey()
 407    {
 408      key_ = new byte[12];
 409      var rnd = new Random();
 410      rnd.NextBytes(key_);
 411    }
 412
 413    /// <summary>
 414    /// Create an encryptor.
 415    /// </summary>
 416    /// <param name="rgbKey">The key to use for this encryptor.</param>
 417    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>
 418    /// <returns>Returns a new PkzipClassic encryptor</returns>
 419    public override ICryptoTransform CreateEncryptor(
 420      byte[] rgbKey,
 421      byte[] rgbIV)
 422    {
 423      key_ = rgbKey;
 424      return new PkzipClassicEncryptCryptoTransform(Key);
 425    }
 426
 427    /// <summary>
 428    /// Create a decryptor.
 429    /// </summary>
 430    /// <param name="rgbKey">Keys to use for this new decryptor.</param>
 431    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>
 432    /// <returns>Returns a new decryptor.</returns>
 433    public override ICryptoTransform CreateDecryptor(
 434      byte[] rgbKey,
 435      byte[] rgbIV)
 436    {
 437      key_ = rgbKey;
 438      return new PkzipClassicDecryptCryptoTransform(Key);
 439    }
 440
 441    #region Instance Fields
 442    byte[] key_;
 443    #endregion
 444  }
 445}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicManaged.htm b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicManaged.htm new file mode 100644 index 000000000..0db63705d --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_PkzipClassicManaged.htm @@ -0,0 +1,490 @@ + + + + +ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs
Covered lines:6
Uncovered lines:22
Coverable lines:28
Total lines:445
Line coverage:21.4%
Branch coverage:12.5%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
GenerateIV()100
GenerateKey()100
CreateEncryptor(...)1100100
CreateDecryptor(...)1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\PkzipClassic.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3using ICSharpCode.SharpZipLib.Checksum;
 4
 5namespace ICSharpCode.SharpZipLib.Encryption
 6{
 7  /// <summary>
 8  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.
 9  /// While it has been superceded by more recent and more powerful algorithms, its still in use and
 10  /// is viable for preventing casual snooping
 11  /// </summary>
 12  public abstract class PkzipClassic : SymmetricAlgorithm
 13  {
 14    /// <summary>
 15    /// Generates new encryption keys based on given seed
 16    /// </summary>
 17    /// <param name="seed">The seed value to initialise keys with.</param>
 18    /// <returns>A new key value.</returns>
 19    static public byte[] GenerateKeys(byte[] seed)
 20    {
 21      if (seed == null) {
 22        throw new ArgumentNullException(nameof(seed));
 23      }
 24
 25      if (seed.Length == 0) {
 26        throw new ArgumentException("Length is zero", nameof(seed));
 27      }
 28
 29      uint[] newKeys = {
 30        0x12345678,
 31        0x23456789,
 32        0x34567890
 33       };
 34
 35      for (int i = 0; i < seed.Length; ++i) {
 36        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);
 37        newKeys[1] = newKeys[1] + (byte)newKeys[0];
 38        newKeys[1] = newKeys[1] * 134775813 + 1;
 39        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));
 40      }
 41
 42      byte[] result = new byte[12];
 43      result[0] = (byte)(newKeys[0] & 0xff);
 44      result[1] = (byte)((newKeys[0] >> 8) & 0xff);
 45      result[2] = (byte)((newKeys[0] >> 16) & 0xff);
 46      result[3] = (byte)((newKeys[0] >> 24) & 0xff);
 47      result[4] = (byte)(newKeys[1] & 0xff);
 48      result[5] = (byte)((newKeys[1] >> 8) & 0xff);
 49      result[6] = (byte)((newKeys[1] >> 16) & 0xff);
 50      result[7] = (byte)((newKeys[1] >> 24) & 0xff);
 51      result[8] = (byte)(newKeys[2] & 0xff);
 52      result[9] = (byte)((newKeys[2] >> 8) & 0xff);
 53      result[10] = (byte)((newKeys[2] >> 16) & 0xff);
 54      result[11] = (byte)((newKeys[2] >> 24) & 0xff);
 55      return result;
 56    }
 57  }
 58
 59  /// <summary>
 60  /// PkzipClassicCryptoBase provides the low level facilities for encryption
 61  /// and decryption using the PkzipClassic algorithm.
 62  /// </summary>
 63  class PkzipClassicCryptoBase
 64  {
 65    /// <summary>
 66    /// Transform a single byte
 67    /// </summary>
 68    /// <returns>
 69    /// The transformed value
 70    /// </returns>
 71    protected byte TransformByte()
 72    {
 73      uint temp = ((keys[2] & 0xFFFF) | 2);
 74      return (byte)((temp * (temp ^ 1)) >> 8);
 75    }
 76
 77    /// <summary>
 78    /// Set the key schedule for encryption/decryption.
 79    /// </summary>
 80    /// <param name="keyData">The data use to set the keys from.</param>
 81    protected void SetKeys(byte[] keyData)
 82    {
 83      if (keyData == null) {
 84        throw new ArgumentNullException(nameof(keyData));
 85      }
 86
 87      if (keyData.Length != 12) {
 88        throw new InvalidOperationException("Key length is not valid");
 89      }
 90
 91      keys = new uint[3];
 92      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);
 93      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);
 94      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);
 95    }
 96
 97    /// <summary>
 98    /// Update encryption keys
 99    /// </summary>
 100    protected void UpdateKeys(byte ch)
 101    {
 102      keys[0] = Crc32.ComputeCrc32(keys[0], ch);
 103      keys[1] = keys[1] + (byte)keys[0];
 104      keys[1] = keys[1] * 134775813 + 1;
 105      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
 106    }
 107
 108    /// <summary>
 109    /// Reset the internal state.
 110    /// </summary>
 111    protected void Reset()
 112    {
 113      keys[0] = 0;
 114      keys[1] = 0;
 115      keys[2] = 0;
 116    }
 117
 118    #region Instance Fields
 119    uint[] keys;
 120    #endregion
 121  }
 122
 123  /// <summary>
 124  /// PkzipClassic CryptoTransform for encryption.
 125  /// </summary>
 126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 127  {
 128    /// <summary>
 129    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>
 130    /// </summary>
 131    /// <param name="keyBlock">The key block to use.</param>
 132    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)
 133    {
 134      SetKeys(keyBlock);
 135    }
 136
 137    #region ICryptoTransform Members
 138
 139    /// <summary>
 140    /// Transforms the specified region of the specified byte array.
 141    /// </summary>
 142    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 143    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 144    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 145    /// <returns>The computed transform.</returns>
 146    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 147    {
 148      byte[] result = new byte[inputCount];
 149      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 150      return result;
 151    }
 152
 153    /// <summary>
 154    /// Transforms the specified region of the input byte array and copies
 155    /// the resulting transform to the specified region of the output byte array.
 156    /// </summary>
 157    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 158    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 159    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 160    /// <param name="outputBuffer">The output to which to write the transform.</param>
 161    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 162    /// <returns>The number of bytes written.</returns>
 163    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 164    {
 165      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 166        byte oldbyte = inputBuffer[i];
 167        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());
 168        UpdateKeys(oldbyte);
 169      }
 170      return inputCount;
 171    }
 172
 173    /// <summary>
 174    /// Gets a value indicating whether the current transform can be reused.
 175    /// </summary>
 176    public bool CanReuseTransform {
 177      get {
 178        return true;
 179      }
 180    }
 181
 182    /// <summary>
 183    /// Gets the size of the input data blocks in bytes.
 184    /// </summary>
 185    public int InputBlockSize {
 186      get {
 187        return 1;
 188      }
 189    }
 190
 191    /// <summary>
 192    /// Gets the size of the output data blocks in bytes.
 193    /// </summary>
 194    public int OutputBlockSize {
 195      get {
 196        return 1;
 197      }
 198    }
 199
 200    /// <summary>
 201    /// Gets a value indicating whether multiple blocks can be transformed.
 202    /// </summary>
 203    public bool CanTransformMultipleBlocks {
 204      get {
 205        return true;
 206      }
 207    }
 208
 209    #endregion
 210
 211    #region IDisposable Members
 212
 213    /// <summary>
 214    /// Cleanup internal state.
 215    /// </summary>
 216    public void Dispose()
 217    {
 218      Reset();
 219    }
 220
 221    #endregion
 222  }
 223
 224
 225  /// <summary>
 226  /// PkzipClassic CryptoTransform for decryption.
 227  /// </summary>
 228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
 229  {
 230    /// <summary>
 231    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.
 232    /// </summary>
 233    /// <param name="keyBlock">The key block to decrypt with.</param>
 234    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)
 235    {
 236      SetKeys(keyBlock);
 237    }
 238
 239    #region ICryptoTransform Members
 240
 241    /// <summary>
 242    /// Transforms the specified region of the specified byte array.
 243    /// </summary>
 244    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 245    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
 246    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
 247    /// <returns>The computed transform.</returns>
 248    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 249    {
 250      byte[] result = new byte[inputCount];
 251      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
 252      return result;
 253    }
 254
 255    /// <summary>
 256    /// Transforms the specified region of the input byte array and copies
 257    /// the resulting transform to the specified region of the output byte array.
 258    /// </summary>
 259    /// <param name="inputBuffer">The input for which to compute the transform.</param>
 260    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 261    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 262    /// <param name="outputBuffer">The output to which to write the transform.</param>
 263    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 264    /// <returns>The number of bytes written.</returns>
 265    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 266    {
 267      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
 268        var newByte = (byte)(inputBuffer[i] ^ TransformByte());
 269        outputBuffer[outputOffset++] = newByte;
 270        UpdateKeys(newByte);
 271      }
 272      return inputCount;
 273    }
 274
 275    /// <summary>
 276    /// Gets a value indicating whether the current transform can be reused.
 277    /// </summary>
 278    public bool CanReuseTransform {
 279      get {
 280        return true;
 281      }
 282    }
 283
 284    /// <summary>
 285    /// Gets the size of the input data blocks in bytes.
 286    /// </summary>
 287    public int InputBlockSize {
 288      get {
 289        return 1;
 290      }
 291    }
 292
 293    /// <summary>
 294    /// Gets the size of the output data blocks in bytes.
 295    /// </summary>
 296    public int OutputBlockSize {
 297      get {
 298        return 1;
 299      }
 300    }
 301
 302    /// <summary>
 303    /// Gets a value indicating whether multiple blocks can be transformed.
 304    /// </summary>
 305    public bool CanTransformMultipleBlocks {
 306      get {
 307        return true;
 308      }
 309    }
 310
 311    #endregion
 312
 313    #region IDisposable Members
 314
 315    /// <summary>
 316    /// Cleanup internal state.
 317    /// </summary>
 318    public void Dispose()
 319    {
 320      Reset();
 321    }
 322
 323    #endregion
 324  }
 325
 326  /// <summary>
 327  /// Defines a wrapper object to access the Pkzip algorithm.
 328  /// This class cannot be inherited.
 329  /// </summary>
 330  public sealed class PkzipClassicManaged : PkzipClassic
 331  {
 332    /// <summary>
 333    /// Get / set the applicable block size in bits.
 334    /// </summary>
 335    /// <remarks>The only valid block size is 8.</remarks>
 336    public override int BlockSize {
 337      get {
 0338        return 8;
 339      }
 340
 341      set {
 0342         if (value != 8) {
 0343          throw new CryptographicException("Block size is invalid");
 344        }
 0345      }
 346    }
 347
 348    /// <summary>
 349    /// Get an array of legal <see cref="KeySizes">key sizes.</see>
 350    /// </summary>
 351    public override KeySizes[] LegalKeySizes {
 352      get {
 0353        KeySizes[] keySizes = new KeySizes[1];
 0354        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);
 0355        return keySizes;
 356      }
 357    }
 358
 359    /// <summary>
 360    /// Generate an initial vector.
 361    /// </summary>
 362    public override void GenerateIV()
 363    {
 364      // Do nothing.
 0365    }
 366
 367    /// <summary>
 368    /// Get an array of legal <see cref="KeySizes">block sizes</see>.
 369    /// </summary>
 370    public override KeySizes[] LegalBlockSizes {
 371      get {
 0372        KeySizes[] keySizes = new KeySizes[1];
 0373        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);
 0374        return keySizes;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Get / set the key value applicable.
 380    /// </summary>
 381    public override byte[] Key {
 382      get {
 72383         if (key_ == null) {
 0384          GenerateKey();
 385        }
 386
 72387        return (byte[])key_.Clone();
 388      }
 389
 390      set {
 0391         if (value == null) {
 0392          throw new ArgumentNullException(nameof(value));
 393        }
 394
 0395         if (value.Length != 12) {
 0396          throw new CryptographicException("Key size is illegal");
 397        }
 398
 0399        key_ = (byte[])value.Clone();
 0400      }
 401    }
 402
 403    /// <summary>
 404    /// Generate a new random key.
 405    /// </summary>
 406    public override void GenerateKey()
 407    {
 0408      key_ = new byte[12];
 0409      var rnd = new Random();
 0410      rnd.NextBytes(key_);
 0411    }
 412
 413    /// <summary>
 414    /// Create an encryptor.
 415    /// </summary>
 416    /// <param name="rgbKey">The key to use for this encryptor.</param>
 417    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>
 418    /// <returns>Returns a new PkzipClassic encryptor</returns>
 419    public override ICryptoTransform CreateEncryptor(
 420      byte[] rgbKey,
 421      byte[] rgbIV)
 422    {
 38423      key_ = rgbKey;
 38424      return new PkzipClassicEncryptCryptoTransform(Key);
 425    }
 426
 427    /// <summary>
 428    /// Create a decryptor.
 429    /// </summary>
 430    /// <param name="rgbKey">Keys to use for this new decryptor.</param>
 431    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>
 432    /// <returns>Returns a new decryptor.</returns>
 433    public override ICryptoTransform CreateDecryptor(
 434      byte[] rgbKey,
 435      byte[] rgbIV)
 436    {
 34437      key_ = rgbKey;
 34438      return new PkzipClassicDecryptCryptoTransform(Key);
 439    }
 440
 441    #region Instance Fields
 442    byte[] key_;
 443    #endregion
 444  }
 445}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ProcessFileHandler.htm b/docs/opencover/ICSharpCode.SharpZipLib_ProcessFileHandler.htm new file mode 100644 index 000000000..76a26ebdb --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ProcessFileHandler.htm @@ -0,0 +1,29 @@ + + + + +ICSharpCode.SharpZipLib.Core.ProcessFileHandler - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.ProcessFileHandler
Assembly:ICSharpCode.SharpZipLib
File(s):
Covered lines:0
Uncovered lines:0
Coverable lines:0
Total lines:0
Line coverage:
+

File(s)

+

No files found. This usually happens if a file isn't covered by a test or the class does not contain any sequence points (e.g. a class that only contains auto properties).

+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ProgressEventArgs.htm b/docs/opencover/ICSharpCode.SharpZipLib_ProgressEventArgs.htm new file mode 100644 index 000000000..00cc0b5b4 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ProgressEventArgs.htm @@ -0,0 +1,517 @@ + + + + +ICSharpCode.SharpZipLib.Core.ProgressEventArgs - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.ProgressEventArgs
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs
Covered lines:0
Uncovered lines:16
Coverable lines:16
Total lines:475
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Core
 4{
 5  #region EventArgs
 6  /// <summary>
 7  /// Event arguments for scanning.
 8  /// </summary>
 9  public class ScanEventArgs : EventArgs
 10  {
 11    #region Constructors
 12    /// <summary>
 13    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 14    /// </summary>
 15    /// <param name="name">The file or directory name.</param>
 16    public ScanEventArgs(string name)
 17    {
 18      name_ = name;
 19    }
 20    #endregion
 21
 22    /// <summary>
 23    /// The file or directory name for this event.
 24    /// </summary>
 25    public string Name {
 26      get { return name_; }
 27    }
 28
 29    /// <summary>
 30    /// Get set a value indicating if scanning should continue or not.
 31    /// </summary>
 32    public bool ContinueRunning {
 33      get { return continueRunning_; }
 34      set { continueRunning_ = value; }
 35    }
 36
 37    #region Instance Fields
 38    string name_;
 39    bool continueRunning_ = true;
 40    #endregion
 41  }
 42
 43  /// <summary>
 44  /// Event arguments during processing of a single file or directory.
 45  /// </summary>
 46  public class ProgressEventArgs : EventArgs
 47  {
 48    #region Constructors
 49    /// <summary>
 50    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 51    /// </summary>
 52    /// <param name="name">The file or directory name if known.</param>
 53    /// <param name="processed">The number of bytes processed so far</param>
 54    /// <param name="target">The total number of bytes to process, 0 if not known</param>
 055    public ProgressEventArgs(string name, long processed, long target)
 56    {
 057      name_ = name;
 058      processed_ = processed;
 059      target_ = target;
 060    }
 61    #endregion
 62
 63    /// <summary>
 64    /// The name for this event if known.
 65    /// </summary>
 66    public string Name {
 067      get { return name_; }
 68    }
 69
 70    /// <summary>
 71    /// Get set a value indicating wether scanning should continue or not.
 72    /// </summary>
 73    public bool ContinueRunning {
 074      get { return continueRunning_; }
 075      set { continueRunning_ = value; }
 76    }
 77
 78    /// <summary>
 79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed
 80    /// </summary>
 81    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>
 82    public float PercentComplete {
 83      get {
 84        float result;
 085         if (target_ <= 0) {
 086          result = 0;
 087        } else {
 088          result = ((float)processed_ / (float)target_) * 100.0f;
 89        }
 090        return result;
 91      }
 92    }
 93
 94    /// <summary>
 95    /// The number of bytes processed so far
 96    /// </summary>
 97    public long Processed {
 098      get { return processed_; }
 99    }
 100
 101    /// <summary>
 102    /// The number of bytes to process.
 103    /// </summary>
 104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>
 105    public long Target {
 0106      get { return target_; }
 107    }
 108
 109    #region Instance Fields
 110    string name_;
 111    long processed_;
 112    long target_;
 0113    bool continueRunning_ = true;
 114    #endregion
 115  }
 116
 117  /// <summary>
 118  /// Event arguments for directories.
 119  /// </summary>
 120  public class DirectoryEventArgs : ScanEventArgs
 121  {
 122    #region Constructors
 123    /// <summary>
 124    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.
 125    /// </summary>
 126    /// <param name="name">The name for this directory.</param>
 127    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par
 128    public DirectoryEventArgs(string name, bool hasMatchingFiles)
 129      : base(name)
 130    {
 131      hasMatchingFiles_ = hasMatchingFiles;
 132    }
 133    #endregion
 134
 135    /// <summary>
 136    /// Get a value indicating if the directory contains any matching files or not.
 137    /// </summary>
 138    public bool HasMatchingFiles {
 139      get { return hasMatchingFiles_; }
 140    }
 141
 142    readonly
 143
 144    #region Instance Fields
 145    bool hasMatchingFiles_;
 146    #endregion
 147  }
 148
 149  /// <summary>
 150  /// Arguments passed when scan failures are detected.
 151  /// </summary>
 152  public class ScanFailureEventArgs : EventArgs
 153  {
 154    #region Constructors
 155    /// <summary>
 156    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>
 157    /// </summary>
 158    /// <param name="name">The name to apply.</param>
 159    /// <param name="e">The exception to use.</param>
 160    public ScanFailureEventArgs(string name, Exception e)
 161    {
 162      name_ = name;
 163      exception_ = e;
 164      continueRunning_ = true;
 165    }
 166    #endregion
 167
 168    /// <summary>
 169    /// The applicable name.
 170    /// </summary>
 171    public string Name {
 172      get { return name_; }
 173    }
 174
 175    /// <summary>
 176    /// The applicable exception.
 177    /// </summary>
 178    public Exception Exception {
 179      get { return exception_; }
 180    }
 181
 182    /// <summary>
 183    /// Get / set a value indicating wether scanning should continue.
 184    /// </summary>
 185    public bool ContinueRunning {
 186      get { return continueRunning_; }
 187      set { continueRunning_ = value; }
 188    }
 189
 190    #region Instance Fields
 191    string name_;
 192    Exception exception_;
 193    bool continueRunning_;
 194    #endregion
 195  }
 196
 197  #endregion
 198
 199  #region Delegates
 200  /// <summary>
 201  /// Delegate invoked before starting to process a file.
 202  /// </summary>
 203  /// <param name="sender">The source of the event</param>
 204  /// <param name="e">The event arguments.</param>
 205  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);
 206
 207  /// <summary>
 208  /// Delegate invoked during processing of a file or directory
 209  /// </summary>
 210  /// <param name="sender">The source of the event</param>
 211  /// <param name="e">The event arguments.</param>
 212  public delegate void ProgressHandler(object sender, ProgressEventArgs e);
 213
 214  /// <summary>
 215  /// Delegate invoked when a file has been completely processed.
 216  /// </summary>
 217  /// <param name="sender">The source of the event</param>
 218  /// <param name="e">The event arguments.</param>
 219  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);
 220
 221  /// <summary>
 222  /// Delegate invoked when a directory failure is detected.
 223  /// </summary>
 224  /// <param name="sender">The source of the event</param>
 225  /// <param name="e">The event arguments.</param>
 226  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);
 227
 228  /// <summary>
 229  /// Delegate invoked when a file failure is detected.
 230  /// </summary>
 231  /// <param name="sender">The source of the event</param>
 232  /// <param name="e">The event arguments.</param>
 233  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);
 234  #endregion
 235
 236  /// <summary>
 237  /// FileSystemScanner provides facilities scanning of files and directories.
 238  /// </summary>
 239  public class FileSystemScanner
 240  {
 241    #region Constructors
 242    /// <summary>
 243    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 244    /// </summary>
 245    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>
 246    public FileSystemScanner(string filter)
 247    {
 248      fileFilter_ = new PathFilter(filter);
 249    }
 250
 251    /// <summary>
 252    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 253    /// </summary>
 254    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
 255    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>
 256    public FileSystemScanner(string fileFilter, string directoryFilter)
 257    {
 258      fileFilter_ = new PathFilter(fileFilter);
 259      directoryFilter_ = new PathFilter(directoryFilter);
 260    }
 261
 262    /// <summary>
 263    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 264    /// </summary>
 265    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
 266    public FileSystemScanner(IScanFilter fileFilter)
 267    {
 268      fileFilter_ = fileFilter;
 269    }
 270
 271    /// <summary>
 272    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 273    /// </summary>
 274    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>
 275    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>
 276    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)
 277    {
 278      fileFilter_ = fileFilter;
 279      directoryFilter_ = directoryFilter;
 280    }
 281    #endregion
 282
 283    #region Delegates
 284    /// <summary>
 285    /// Delegate to invoke when a directory is processed.
 286    /// </summary>
 287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;
 288
 289    /// <summary>
 290    /// Delegate to invoke when a file is processed.
 291    /// </summary>
 292    public ProcessFileHandler ProcessFile;
 293
 294    /// <summary>
 295    /// Delegate to invoke when processing for a file has finished.
 296    /// </summary>
 297    public CompletedFileHandler CompletedFile;
 298
 299    /// <summary>
 300    /// Delegate to invoke when a directory failure is detected.
 301    /// </summary>
 302    public DirectoryFailureHandler DirectoryFailure;
 303
 304    /// <summary>
 305    /// Delegate to invoke when a file failure is detected.
 306    /// </summary>
 307    public FileFailureHandler FileFailure;
 308    #endregion
 309
 310    /// <summary>
 311    /// Raise the DirectoryFailure event.
 312    /// </summary>
 313    /// <param name="directory">The directory name.</param>
 314    /// <param name="e">The exception detected.</param>
 315    bool OnDirectoryFailure(string directory, Exception e)
 316    {
 317      DirectoryFailureHandler handler = DirectoryFailure;
 318      bool result = (handler != null);
 319      if (result) {
 320        var args = new ScanFailureEventArgs(directory, e);
 321        handler(this, args);
 322        alive_ = args.ContinueRunning;
 323      }
 324      return result;
 325    }
 326
 327    /// <summary>
 328    /// Raise the FileFailure event.
 329    /// </summary>
 330    /// <param name="file">The file name.</param>
 331    /// <param name="e">The exception detected.</param>
 332    bool OnFileFailure(string file, Exception e)
 333    {
 334      FileFailureHandler handler = FileFailure;
 335
 336      bool result = (handler != null);
 337
 338      if (result) {
 339        var args = new ScanFailureEventArgs(file, e);
 340        FileFailure(this, args);
 341        alive_ = args.ContinueRunning;
 342      }
 343      return result;
 344    }
 345
 346    /// <summary>
 347    /// Raise the ProcessFile event.
 348    /// </summary>
 349    /// <param name="file">The file name.</param>
 350    void OnProcessFile(string file)
 351    {
 352      ProcessFileHandler handler = ProcessFile;
 353
 354      if (handler != null) {
 355        var args = new ScanEventArgs(file);
 356        handler(this, args);
 357        alive_ = args.ContinueRunning;
 358      }
 359    }
 360
 361    /// <summary>
 362    /// Raise the complete file event
 363    /// </summary>
 364    /// <param name="file">The file name</param>
 365    void OnCompleteFile(string file)
 366    {
 367      CompletedFileHandler handler = CompletedFile;
 368
 369      if (handler != null) {
 370        var args = new ScanEventArgs(file);
 371        handler(this, args);
 372        alive_ = args.ContinueRunning;
 373      }
 374    }
 375
 376    /// <summary>
 377    /// Raise the ProcessDirectory event.
 378    /// </summary>
 379    /// <param name="directory">The directory name.</param>
 380    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>
 381    void OnProcessDirectory(string directory, bool hasMatchingFiles)
 382    {
 383      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;
 384
 385      if (handler != null) {
 386        var args = new DirectoryEventArgs(directory, hasMatchingFiles);
 387        handler(this, args);
 388        alive_ = args.ContinueRunning;
 389      }
 390    }
 391
 392    /// <summary>
 393    /// Scan a directory.
 394    /// </summary>
 395    /// <param name="directory">The base directory to scan.</param>
 396    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>
 397    public void Scan(string directory, bool recurse)
 398    {
 399      alive_ = true;
 400      ScanDir(directory, recurse);
 401    }
 402
 403    void ScanDir(string directory, bool recurse)
 404    {
 405
 406      try {
 407        string[] names = System.IO.Directory.GetFiles(directory);
 408        bool hasMatch = false;
 409        for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {
 410          if (!fileFilter_.IsMatch(names[fileIndex])) {
 411            names[fileIndex] = null;
 412          } else {
 413            hasMatch = true;
 414          }
 415        }
 416
 417        OnProcessDirectory(directory, hasMatch);
 418
 419        if (alive_ && hasMatch) {
 420          foreach (string fileName in names) {
 421            try {
 422              if (fileName != null) {
 423                OnProcessFile(fileName);
 424                if (!alive_) {
 425                  break;
 426                }
 427              }
 428            } catch (Exception e) {
 429              if (!OnFileFailure(fileName, e)) {
 430                throw;
 431              }
 432            }
 433          }
 434        }
 435      } catch (Exception e) {
 436        if (!OnDirectoryFailure(directory, e)) {
 437          throw;
 438        }
 439      }
 440
 441      if (alive_ && recurse) {
 442        try {
 443          string[] names = System.IO.Directory.GetDirectories(directory);
 444          foreach (string fulldir in names) {
 445            if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {
 446              ScanDir(fulldir, true);
 447              if (!alive_) {
 448                break;
 449              }
 450            }
 451          }
 452        } catch (Exception e) {
 453          if (!OnDirectoryFailure(directory, e)) {
 454            throw;
 455          }
 456        }
 457      }
 458    }
 459
 460    #region Instance Fields
 461    /// <summary>
 462    /// The file filter currently in use.
 463    /// </summary>
 464    IScanFilter fileFilter_;
 465    /// <summary>
 466    /// The directory filter currently in use.
 467    /// </summary>
 468    IScanFilter directoryFilter_;
 469    /// <summary>
 470    /// Flag indicating if scanning should continue running.
 471    /// </summary>
 472    bool alive_;
 473    #endregion
 474  }
 475}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ProgressHandler.htm b/docs/opencover/ICSharpCode.SharpZipLib_ProgressHandler.htm new file mode 100644 index 000000000..5180ae3a9 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ProgressHandler.htm @@ -0,0 +1,29 @@ + + + + +ICSharpCode.SharpZipLib.Core.ProgressHandler - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.ProgressHandler
Assembly:ICSharpCode.SharpZipLib
File(s):
Covered lines:0
Uncovered lines:0
Coverable lines:0
Total lines:0
Line coverage:
+

File(s)

+

No files found. This usually happens if a file isn't covered by a test or the class does not contain any sequence points (e.g. a class that only contains auto properties).

+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ProgressMessageHandler.htm b/docs/opencover/ICSharpCode.SharpZipLib_ProgressMessageHandler.htm new file mode 100644 index 000000000..1d12148d5 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ProgressMessageHandler.htm @@ -0,0 +1,29 @@ + + + + +ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler
Assembly:ICSharpCode.SharpZipLib
File(s):
Covered lines:0
Uncovered lines:0
Coverable lines:0
Total lines:0
Line coverage:
+

File(s)

+

No files found. This usually happens if a file isn't covered by a test or the class does not contain any sequence points (e.g. a class that only contains auto properties).

+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_RawTaggedData.htm b/docs/opencover/ICSharpCode.SharpZipLib_RawTaggedData.htm new file mode 100644 index 000000000..9585e12fe --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_RawTaggedData.htm @@ -0,0 +1,940 @@ + + + + +ICSharpCode.SharpZipLib.Zip.RawTaggedData - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.RawTaggedData
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipExtraData.cs
Covered lines:0
Uncovered lines:13
Coverable lines:13
Total lines:896
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
SetData(...)200
GetData()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipExtraData.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Zip
 5{
 6  // TODO: Sort out wether tagged data is useful and what a good implementation might look like.
 7  // Its just a sketch of an idea at the moment.
 8
 9  /// <summary>
 10  /// ExtraData tagged value interface.
 11  /// </summary>
 12  public interface ITaggedData
 13  {
 14    /// <summary>
 15    /// Get the ID for this tagged data value.
 16    /// </summary>
 17    short TagID { get; }
 18
 19    /// <summary>
 20    /// Set the contents of this instance from the data passed.
 21    /// </summary>
 22    /// <param name="data">The data to extract contents from.</param>
 23    /// <param name="offset">The offset to begin extracting data from.</param>
 24    /// <param name="count">The number of bytes to extract.</param>
 25    void SetData(byte[] data, int offset, int count);
 26
 27    /// <summary>
 28    /// Get the data representing this instance.
 29    /// </summary>
 30    /// <returns>Returns the data for this instance.</returns>
 31    byte[] GetData();
 32  }
 33
 34  /// <summary>
 35  /// A raw binary tagged value
 36  /// </summary>
 37  public class RawTaggedData : ITaggedData
 38  {
 39    /// <summary>
 40    /// Initialise a new instance.
 41    /// </summary>
 42    /// <param name="tag">The tag ID.</param>
 043    public RawTaggedData(short tag)
 44    {
 045      _tag = tag;
 046    }
 47
 48    #region ITaggedData Members
 49
 50    /// <summary>
 51    /// Get the ID for this tagged data value.
 52    /// </summary>
 53    public short TagID {
 054      get { return _tag; }
 055      set { _tag = value; }
 56    }
 57
 58    /// <summary>
 59    /// Set the data from the raw values provided.
 60    /// </summary>
 61    /// <param name="data">The raw data to extract values from.</param>
 62    /// <param name="offset">The index to start extracting values from.</param>
 63    /// <param name="count">The number of bytes available.</param>
 64    public void SetData(byte[] data, int offset, int count)
 65    {
 066       if (data == null) {
 067        throw new ArgumentNullException(nameof(data));
 68      }
 69
 070      _data = new byte[count];
 071      Array.Copy(data, offset, _data, 0, count);
 072    }
 73
 74    /// <summary>
 75    /// Get the binary data representing this instance.
 76    /// </summary>
 77    /// <returns>The raw binary data representing this instance.</returns>
 78    public byte[] GetData()
 79    {
 080      return _data;
 81    }
 82
 83    #endregion
 84
 85    /// <summary>
 86    /// Get /set the binary data representing this instance.
 87    /// </summary>
 88    /// <returns>The raw binary data representing this instance.</returns>
 89    public byte[] Data {
 090      get { return _data; }
 091      set { _data = value; }
 92    }
 93
 94    #region Instance Fields
 95    /// <summary>
 96    /// The tag ID for this instance.
 97    /// </summary>
 98    short _tag;
 99
 100    byte[] _data;
 101    #endregion
 102  }
 103
 104  /// <summary>
 105  /// Class representing extended unix date time values.
 106  /// </summary>
 107  public class ExtendedUnixData : ITaggedData
 108  {
 109    /// <summary>
 110    /// Flags indicate which values are included in this instance.
 111    /// </summary>
 112    [Flags]
 113    public enum Flags : byte
 114    {
 115      /// <summary>
 116      /// The modification time is included
 117      /// </summary>
 118      ModificationTime = 0x01,
 119
 120      /// <summary>
 121      /// The access time is included
 122      /// </summary>
 123      AccessTime = 0x02,
 124
 125      /// <summary>
 126      /// The create time is included.
 127      /// </summary>
 128      CreateTime = 0x04,
 129    }
 130
 131    #region ITaggedData Members
 132
 133    /// <summary>
 134    /// Get the ID
 135    /// </summary>
 136    public short TagID {
 137      get { return 0x5455; }
 138    }
 139
 140    /// <summary>
 141    /// Set the data from the raw values provided.
 142    /// </summary>
 143    /// <param name="data">The raw data to extract values from.</param>
 144    /// <param name="index">The index to start extracting values from.</param>
 145    /// <param name="count">The number of bytes available.</param>
 146    public void SetData(byte[] data, int index, int count)
 147    {
 148      using (MemoryStream ms = new MemoryStream(data, index, count, false))
 149      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 150        // bit 0           if set, modification time is present
 151        // bit 1           if set, access time is present
 152        // bit 2           if set, creation time is present
 153
 154        _flags = (Flags)helperStream.ReadByte();
 155        if (((_flags & Flags.ModificationTime) != 0))
 156        {
 157          int iTime = helperStream.ReadLEInt();
 158
 159          _modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 160            new TimeSpan(0, 0, 0, iTime, 0);
 161
 162          // Central-header version is truncated after modification time
 163          if (count <= 5) return;
 164        }
 165
 166        if ((_flags & Flags.AccessTime) != 0) {
 167          int iTime = helperStream.ReadLEInt();
 168
 169          _lastAccessTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 170            new TimeSpan(0, 0, 0, iTime, 0);
 171        }
 172
 173        if ((_flags & Flags.CreateTime) != 0) {
 174          int iTime = helperStream.ReadLEInt();
 175
 176          _createTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 177            new TimeSpan(0, 0, 0, iTime, 0);
 178        }
 179      }
 180    }
 181
 182    /// <summary>
 183    /// Get the binary data representing this instance.
 184    /// </summary>
 185    /// <returns>The raw binary data representing this instance.</returns>
 186    public byte[] GetData()
 187    {
 188      using (MemoryStream ms = new MemoryStream())
 189      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 190        helperStream.IsStreamOwner = false;
 191        helperStream.WriteByte((byte)_flags);     // Flags
 192        if ((_flags & Flags.ModificationTime) != 0) {
 193          TimeSpan span = _modificationTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 194          var seconds = (int)span.TotalSeconds;
 195          helperStream.WriteLEInt(seconds);
 196        }
 197        if ((_flags & Flags.AccessTime) != 0) {
 198          TimeSpan span = _lastAccessTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 199          var seconds = (int)span.TotalSeconds;
 200          helperStream.WriteLEInt(seconds);
 201        }
 202        if ((_flags & Flags.CreateTime) != 0) {
 203          TimeSpan span = _createTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 204          var seconds = (int)span.TotalSeconds;
 205          helperStream.WriteLEInt(seconds);
 206        }
 207        return ms.ToArray();
 208      }
 209    }
 210
 211    #endregion
 212
 213    /// <summary>
 214    /// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>
 215    /// </summary>
 216    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 217    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 218    /// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,
 219    /// which is the number of seconds since 1970-01-01.
 220    /// Being 32 bits means the values here cover a range of about 136 years.
 221    /// The minimum representable time is 1901-12-13 20:45:52,
 222    /// and the maximum representable time is 2038-01-19 03:14:07.
 223    /// </remarks>
 224    public static bool IsValidValue(DateTime value)
 225    {
 226      return ((value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||
 227          (value <= new DateTime(2038, 1, 19, 03, 14, 07)));
 228    }
 229
 230    /// <summary>
 231    /// Get /set the Modification Time
 232    /// </summary>
 233    /// <exception cref="ArgumentOutOfRangeException"></exception>
 234    /// <seealso cref="IsValidValue"></seealso>
 235    public DateTime ModificationTime {
 236      get { return _modificationTime; }
 237      set {
 238        if (!IsValidValue(value)) {
 239          throw new ArgumentOutOfRangeException(nameof(value));
 240        }
 241
 242        _flags |= Flags.ModificationTime;
 243        _modificationTime = value;
 244      }
 245    }
 246
 247    /// <summary>
 248    /// Get / set the Access Time
 249    /// </summary>
 250    /// <exception cref="ArgumentOutOfRangeException"></exception>
 251    /// <seealso cref="IsValidValue"></seealso>
 252    public DateTime AccessTime {
 253      get { return _lastAccessTime; }
 254      set {
 255        if (!IsValidValue(value)) {
 256          throw new ArgumentOutOfRangeException(nameof(value));
 257        }
 258
 259        _flags |= Flags.AccessTime;
 260        _lastAccessTime = value;
 261      }
 262    }
 263
 264    /// <summary>
 265    /// Get / Set the Create Time
 266    /// </summary>
 267    /// <exception cref="ArgumentOutOfRangeException"></exception>
 268    /// <seealso cref="IsValidValue"></seealso>
 269    public DateTime CreateTime {
 270      get { return _createTime; }
 271      set {
 272        if (!IsValidValue(value)) {
 273          throw new ArgumentOutOfRangeException(nameof(value));
 274        }
 275
 276        _flags |= Flags.CreateTime;
 277        _createTime = value;
 278      }
 279    }
 280
 281    /// <summary>
 282    /// Get/set the <see cref="Flags">values</see> to include.
 283    /// </summary>
 284    public Flags Include
 285    {
 286      get { return _flags; }
 287      set { _flags = value; }
 288    }
 289
 290    #region Instance Fields
 291    Flags _flags;
 292    DateTime _modificationTime = new DateTime(1970, 1, 1);
 293    DateTime _lastAccessTime = new DateTime(1970, 1, 1);
 294    DateTime _createTime = new DateTime(1970, 1, 1);
 295    #endregion
 296  }
 297
 298  /// <summary>
 299  /// Class handling NT date time values.
 300  /// </summary>
 301  public class NTTaggedData : ITaggedData
 302  {
 303    /// <summary>
 304    /// Get the ID for this tagged data value.
 305    /// </summary>
 306    public short TagID {
 307      get { return 10; }
 308    }
 309
 310    /// <summary>
 311    /// Set the data from the raw values provided.
 312    /// </summary>
 313    /// <param name="data">The raw data to extract values from.</param>
 314    /// <param name="index">The index to start extracting values from.</param>
 315    /// <param name="count">The number of bytes available.</param>
 316    public void SetData(byte[] data, int index, int count)
 317    {
 318      using (MemoryStream ms = new MemoryStream(data, index, count, false))
 319      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 320        helperStream.ReadLEInt(); // Reserved
 321        while (helperStream.Position < helperStream.Length) {
 322          int ntfsTag = helperStream.ReadLEShort();
 323          int ntfsLength = helperStream.ReadLEShort();
 324          if (ntfsTag == 1) {
 325            if (ntfsLength >= 24) {
 326              long lastModificationTicks = helperStream.ReadLELong();
 327              _lastModificationTime = DateTime.FromFileTimeUtc(lastModificationTicks);
 328
 329              long lastAccessTicks = helperStream.ReadLELong();
 330              _lastAccessTime = DateTime.FromFileTimeUtc(lastAccessTicks);
 331
 332              long createTimeTicks = helperStream.ReadLELong();
 333              _createTime = DateTime.FromFileTimeUtc(createTimeTicks);
 334            }
 335            break;
 336          } else {
 337            // An unknown NTFS tag so simply skip it.
 338            helperStream.Seek(ntfsLength, SeekOrigin.Current);
 339          }
 340        }
 341      }
 342    }
 343
 344    /// <summary>
 345    /// Get the binary data representing this instance.
 346    /// </summary>
 347    /// <returns>The raw binary data representing this instance.</returns>
 348    public byte[] GetData()
 349    {
 350      using (MemoryStream ms = new MemoryStream())
 351      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 352        helperStream.IsStreamOwner = false;
 353        helperStream.WriteLEInt(0);       // Reserved
 354        helperStream.WriteLEShort(1);     // Tag
 355        helperStream.WriteLEShort(24);    // Length = 3 x 8.
 356        helperStream.WriteLELong(_lastModificationTime.ToFileTimeUtc());
 357        helperStream.WriteLELong(_lastAccessTime.ToFileTimeUtc());
 358        helperStream.WriteLELong(_createTime.ToFileTimeUtc());
 359        return ms.ToArray();
 360      }
 361    }
 362
 363    /// <summary>
 364    /// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>
 365    /// </summary>
 366    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 367    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 368    /// <remarks>
 369    /// NTFS filetimes are 64-bit unsigned integers, stored in Intel
 370    /// (least significant byte first) byte order. They determine the
 371    /// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
 372    /// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit
 373    /// </remarks>
 374    public static bool IsValidValue(DateTime value)
 375    {
 376      bool result = true;
 377      try {
 378        value.ToFileTimeUtc();
 379      } catch {
 380        result = false;
 381      }
 382      return result;
 383    }
 384
 385    /// <summary>
 386    /// Get/set the <see cref="DateTime">last modification time</see>.
 387    /// </summary>
 388    public DateTime LastModificationTime {
 389      get { return _lastModificationTime; }
 390      set {
 391        if (!IsValidValue(value)) {
 392          throw new ArgumentOutOfRangeException(nameof(value));
 393        }
 394        _lastModificationTime = value;
 395      }
 396    }
 397
 398    /// <summary>
 399    /// Get /set the <see cref="DateTime">create time</see>
 400    /// </summary>
 401    public DateTime CreateTime {
 402      get { return _createTime; }
 403      set {
 404        if (!IsValidValue(value)) {
 405          throw new ArgumentOutOfRangeException(nameof(value));
 406        }
 407        _createTime = value;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Get /set the <see cref="DateTime">last access time</see>.
 413    /// </summary>
 414    public DateTime LastAccessTime {
 415      get { return _lastAccessTime; }
 416      set {
 417        if (!IsValidValue(value)) {
 418          throw new ArgumentOutOfRangeException(nameof(value));
 419        }
 420        _lastAccessTime = value;
 421      }
 422    }
 423
 424    #region Instance Fields
 425    DateTime _lastAccessTime = DateTime.FromFileTimeUtc(0);
 426    DateTime _lastModificationTime = DateTime.FromFileTimeUtc(0);
 427    DateTime _createTime = DateTime.FromFileTimeUtc(0);
 428    #endregion
 429  }
 430
 431  /// <summary>
 432  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.
 433  /// </summary>
 434  interface ITaggedDataFactory
 435  {
 436    /// <summary>
 437    /// Get data for a specific tag value.
 438    /// </summary>
 439    /// <param name="tag">The tag ID to find.</param>
 440    /// <param name="data">The data to search.</param>
 441    /// <param name="offset">The offset to begin extracting data from.</param>
 442    /// <param name="count">The number of bytes to extract.</param>
 443    /// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>
 444    ITaggedData Create(short tag, byte[] data, int offset, int count);
 445  }
 446
 447  ///
 448  /// <summary>
 449  /// A class to handle the extra data field for Zip entries
 450  /// </summary>
 451  /// <remarks>
 452  /// Extra data contains 0 or more values each prefixed by a header tag and length.
 453  /// They contain zero or more bytes of actual data.
 454  /// The data is held internally using a copy on write strategy.  This is more efficient but
 455  /// means that for extra data created by passing in data can have the values modified by the caller
 456  /// in some circumstances.
 457  /// </remarks>
 458  sealed public class ZipExtraData : IDisposable
 459  {
 460    #region Constructors
 461    /// <summary>
 462    /// Initialise a default instance.
 463    /// </summary>
 464    public ZipExtraData()
 465    {
 466      Clear();
 467    }
 468
 469    /// <summary>
 470    /// Initialise with known extra data.
 471    /// </summary>
 472    /// <param name="data">The extra data.</param>
 473    public ZipExtraData(byte[] data)
 474    {
 475      if (data == null) {
 476        _data = new byte[0];
 477      } else {
 478        _data = data;
 479      }
 480    }
 481    #endregion
 482
 483    /// <summary>
 484    /// Get the raw extra data value
 485    /// </summary>
 486    /// <returns>Returns the raw byte[] extra data this instance represents.</returns>
 487    public byte[] GetEntryData()
 488    {
 489      if (Length > ushort.MaxValue) {
 490        throw new ZipException("Data exceeds maximum length");
 491      }
 492
 493      return (byte[])_data.Clone();
 494    }
 495
 496    /// <summary>
 497    /// Clear the stored data.
 498    /// </summary>
 499    public void Clear()
 500    {
 501      if ((_data == null) || (_data.Length != 0)) {
 502        _data = new byte[0];
 503      }
 504    }
 505
 506    /// <summary>
 507    /// Gets the current extra data length.
 508    /// </summary>
 509    public int Length {
 510      get { return _data.Length; }
 511    }
 512
 513    /// <summary>
 514    /// Get a read-only <see cref="Stream"/> for the associated tag.
 515    /// </summary>
 516    /// <param name="tag">The tag to locate data for.</param>
 517    /// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>
 518    public Stream GetStreamForTag(int tag)
 519    {
 520      Stream result = null;
 521      if (Find(tag)) {
 522        result = new MemoryStream(_data, _index, _readValueLength, false);
 523      }
 524      return result;
 525    }
 526
 527    /// <summary>
 528    /// Get the <see cref="ITaggedData">tagged data</see> for a tag.
 529    /// </summary>
 530    /// <typeparam name="T">The tag to search for.</typeparam>
 531    /// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>
 532    public T GetData<T>()
 533      where T : class, ITaggedData, new()
 534    {
 535      T result = new T();
 536      if (Find(result.TagID))
 537      {
 538        result.SetData(_data, _readValueStart, _readValueLength);
 539        return result;
 540      }
 541      else return null;
 542    }
 543
 544    /// <summary>
 545    /// Get the length of the last value found by <see cref="Find"/>
 546    /// </summary>
 547    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.</remarks>
 548    public int ValueLength {
 549      get { return _readValueLength; }
 550    }
 551
 552    /// <summary>
 553    /// Get the index for the current read value.
 554    /// </summary>
 555    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.
 556    /// Initially the result will be the index of the first byte of actual data.  The value is updated after calls to
 557    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>
 558    public int CurrentReadIndex {
 559      get { return _index; }
 560    }
 561
 562    /// <summary>
 563    /// Get the number of bytes remaining to be read for the current value;
 564    /// </summary>
 565    public int UnreadCount {
 566      get {
 567        if ((_readValueStart > _data.Length) ||
 568          (_readValueStart < 4)) {
 569          throw new ZipException("Find must be called before calling a Read method");
 570        }
 571
 572        return _readValueStart + _readValueLength - _index;
 573      }
 574    }
 575
 576    /// <summary>
 577    /// Find an extra data value
 578    /// </summary>
 579    /// <param name="headerID">The identifier for the value to find.</param>
 580    /// <returns>Returns true if the value was found; false otherwise.</returns>
 581    public bool Find(int headerID)
 582    {
 583      _readValueStart = _data.Length;
 584      _readValueLength = 0;
 585      _index = 0;
 586
 587      int localLength = _readValueStart;
 588      int localTag = headerID - 1;
 589
 590      // Trailing bytes that cant make up an entry (as there arent enough
 591      // bytes for a tag and length) are ignored!
 592      while ((localTag != headerID) && (_index < _data.Length - 3)) {
 593        localTag = ReadShortInternal();
 594        localLength = ReadShortInternal();
 595        if (localTag != headerID) {
 596          _index += localLength;
 597        }
 598      }
 599
 600      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);
 601
 602      if (result) {
 603        _readValueStart = _index;
 604        _readValueLength = localLength;
 605      }
 606
 607      return result;
 608    }
 609
 610    /// <summary>
 611    /// Add a new entry to extra data.
 612    /// </summary>
 613    /// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>
 614    public void AddEntry(ITaggedData taggedData)
 615    {
 616      if (taggedData == null) {
 617        throw new ArgumentNullException(nameof(taggedData));
 618      }
 619      AddEntry(taggedData.TagID, taggedData.GetData());
 620    }
 621
 622    /// <summary>
 623    /// Add a new entry to extra data
 624    /// </summary>
 625    /// <param name="headerID">The ID for this entry.</param>
 626    /// <param name="fieldData">The data to add.</param>
 627    /// <remarks>If the ID already exists its contents are replaced.</remarks>
 628    public void AddEntry(int headerID, byte[] fieldData)
 629    {
 630      if ((headerID > ushort.MaxValue) || (headerID < 0)) {
 631        throw new ArgumentOutOfRangeException(nameof(headerID));
 632      }
 633
 634      int addLength = (fieldData == null) ? 0 : fieldData.Length;
 635
 636      if (addLength > ushort.MaxValue) {
 637        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");
 638      }
 639
 640      // Test for new length before adjusting data.
 641      int newLength = _data.Length + addLength + 4;
 642
 643      if (Find(headerID)) {
 644        newLength -= (ValueLength + 4);
 645      }
 646
 647      if (newLength > ushort.MaxValue) {
 648        throw new ZipException("Data exceeds maximum length");
 649      }
 650
 651      Delete(headerID);
 652
 653      byte[] newData = new byte[newLength];
 654      _data.CopyTo(newData, 0);
 655      int index = _data.Length;
 656      _data = newData;
 657      SetShort(ref index, headerID);
 658      SetShort(ref index, addLength);
 659      if (fieldData != null) {
 660        fieldData.CopyTo(newData, index);
 661      }
 662    }
 663
 664    /// <summary>
 665    /// Start adding a new entry.
 666    /// </summary>
 667    /// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see
 668    /// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>
 669    /// <seealso cref="AddEntry(ITaggedData)"/>
 670    public void StartNewEntry()
 671    {
 672      _newEntry = new MemoryStream();
 673    }
 674
 675    /// <summary>
 676    /// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.
 677    /// </summary>
 678    /// <param name="headerID">The identifier to use for this entry.</param>
 679    public void AddNewEntry(int headerID)
 680    {
 681      byte[] newData = _newEntry.ToArray();
 682      _newEntry = null;
 683      AddEntry(headerID, newData);
 684    }
 685
 686    /// <summary>
 687    /// Add a byte of data to the pending new entry.
 688    /// </summary>
 689    /// <param name="data">The byte to add.</param>
 690    /// <seealso cref="StartNewEntry"/>
 691    public void AddData(byte data)
 692    {
 693      _newEntry.WriteByte(data);
 694    }
 695
 696    /// <summary>
 697    /// Add data to a pending new entry.
 698    /// </summary>
 699    /// <param name="data">The data to add.</param>
 700    /// <seealso cref="StartNewEntry"/>
 701    public void AddData(byte[] data)
 702    {
 703      if (data == null) {
 704        throw new ArgumentNullException(nameof(data));
 705      }
 706
 707      _newEntry.Write(data, 0, data.Length);
 708    }
 709
 710    /// <summary>
 711    /// Add a short value in little endian order to the pending new entry.
 712    /// </summary>
 713    /// <param name="toAdd">The data to add.</param>
 714    /// <seealso cref="StartNewEntry"/>
 715    public void AddLeShort(int toAdd)
 716    {
 717      unchecked {
 718        _newEntry.WriteByte((byte)toAdd);
 719        _newEntry.WriteByte((byte)(toAdd >> 8));
 720      }
 721    }
 722
 723    /// <summary>
 724    /// Add an integer value in little endian order to the pending new entry.
 725    /// </summary>
 726    /// <param name="toAdd">The data to add.</param>
 727    /// <seealso cref="StartNewEntry"/>
 728    public void AddLeInt(int toAdd)
 729    {
 730      unchecked {
 731        AddLeShort((short)toAdd);
 732        AddLeShort((short)(toAdd >> 16));
 733      }
 734    }
 735
 736    /// <summary>
 737    /// Add a long value in little endian order to the pending new entry.
 738    /// </summary>
 739    /// <param name="toAdd">The data to add.</param>
 740    /// <seealso cref="StartNewEntry"/>
 741    public void AddLeLong(long toAdd)
 742    {
 743      unchecked {
 744        AddLeInt((int)(toAdd & 0xffffffff));
 745        AddLeInt((int)(toAdd >> 32));
 746      }
 747    }
 748
 749    /// <summary>
 750    /// Delete an extra data field.
 751    /// </summary>
 752    /// <param name="headerID">The identifier of the field to delete.</param>
 753    /// <returns>Returns true if the field was found and deleted.</returns>
 754    public bool Delete(int headerID)
 755    {
 756      bool result = false;
 757
 758      if (Find(headerID)) {
 759        result = true;
 760        int trueStart = _readValueStart - 4;
 761
 762        byte[] newData = new byte[_data.Length - (ValueLength + 4)];
 763        Array.Copy(_data, 0, newData, 0, trueStart);
 764
 765        int trueEnd = trueStart + ValueLength + 4;
 766        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);
 767        _data = newData;
 768      }
 769      return result;
 770    }
 771
 772    #region Reading Support
 773    /// <summary>
 774    /// Read a long in little endian form from the last <see cref="Find">found</see> data value
 775    /// </summary>
 776    /// <returns>Returns the long value read.</returns>
 777    public long ReadLong()
 778    {
 779      ReadCheck(8);
 780      return (ReadInt() & 0xffffffff) | (((long)ReadInt()) << 32);
 781    }
 782
 783    /// <summary>
 784    /// Read an integer in little endian form from the last <see cref="Find">found</see> data value.
 785    /// </summary>
 786    /// <returns>Returns the integer read.</returns>
 787    public int ReadInt()
 788    {
 789      ReadCheck(4);
 790
 791      int result = _data[_index] + (_data[_index + 1] << 8) +
 792        (_data[_index + 2] << 16) + (_data[_index + 3] << 24);
 793      _index += 4;
 794      return result;
 795    }
 796
 797    /// <summary>
 798    /// Read a short value in little endian form from the last <see cref="Find">found</see> data value.
 799    /// </summary>
 800    /// <returns>Returns the short value read.</returns>
 801    public int ReadShort()
 802    {
 803      ReadCheck(2);
 804      int result = _data[_index] + (_data[_index + 1] << 8);
 805      _index += 2;
 806      return result;
 807    }
 808
 809    /// <summary>
 810    /// Read a byte from an extra data
 811    /// </summary>
 812    /// <returns>The byte value read or -1 if the end of data has been reached.</returns>
 813    public int ReadByte()
 814    {
 815      int result = -1;
 816      if ((_index < _data.Length) && (_readValueStart + _readValueLength > _index)) {
 817        result = _data[_index];
 818        _index += 1;
 819      }
 820      return result;
 821    }
 822
 823    /// <summary>
 824    /// Skip data during reading.
 825    /// </summary>
 826    /// <param name="amount">The number of bytes to skip.</param>
 827    public void Skip(int amount)
 828    {
 829      ReadCheck(amount);
 830      _index += amount;
 831    }
 832
 833    void ReadCheck(int length)
 834    {
 835      if ((_readValueStart > _data.Length) ||
 836        (_readValueStart < 4)) {
 837        throw new ZipException("Find must be called before calling a Read method");
 838      }
 839
 840      if (_index > _readValueStart + _readValueLength - length) {
 841        throw new ZipException("End of extra data");
 842      }
 843
 844      if (_index + length < 4) {
 845        throw new ZipException("Cannot read before start of tag");
 846      }
 847    }
 848
 849    /// <summary>
 850    /// Internal form of <see cref="ReadShort"/> that reads data at any location.
 851    /// </summary>
 852    /// <returns>Returns the short value read.</returns>
 853    int ReadShortInternal()
 854    {
 855      if (_index > _data.Length - 2) {
 856        throw new ZipException("End of extra data");
 857      }
 858
 859      int result = _data[_index] + (_data[_index + 1] << 8);
 860      _index += 2;
 861      return result;
 862    }
 863
 864    void SetShort(ref int index, int source)
 865    {
 866      _data[index] = (byte)source;
 867      _data[index + 1] = (byte)(source >> 8);
 868      index += 2;
 869    }
 870
 871    #endregion
 872
 873    #region IDisposable Members
 874
 875    /// <summary>
 876    /// Dispose of this instance.
 877    /// </summary>
 878    public void Dispose()
 879    {
 880      if (_newEntry != null) {
 881        _newEntry.Close();
 882      }
 883    }
 884
 885    #endregion
 886
 887    #region Instance Fields
 888    int _index;
 889    int _readValueStart;
 890    int _readValueLength;
 891
 892    MemoryStream _newEntry;
 893    byte[] _data;
 894    #endregion
 895  }
 896}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ScanEventArgs.htm b/docs/opencover/ICSharpCode.SharpZipLib_ScanEventArgs.htm new file mode 100644 index 000000000..b00a12c01 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ScanEventArgs.htm @@ -0,0 +1,516 @@ + + + + +ICSharpCode.SharpZipLib.Core.ScanEventArgs - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.ScanEventArgs
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs
Covered lines:6
Uncovered lines:1
Coverable lines:7
Total lines:475
Line coverage:85.7%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Core
 4{
 5  #region EventArgs
 6  /// <summary>
 7  /// Event arguments for scanning.
 8  /// </summary>
 9  public class ScanEventArgs : EventArgs
 10  {
 11    #region Constructors
 12    /// <summary>
 13    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 14    /// </summary>
 15    /// <param name="name">The file or directory name.</param>
 416    public ScanEventArgs(string name)
 17    {
 418      name_ = name;
 419    }
 20    #endregion
 21
 22    /// <summary>
 23    /// The file or directory name for this event.
 24    /// </summary>
 25    public string Name {
 1226      get { return name_; }
 27    }
 28
 29    /// <summary>
 30    /// Get set a value indicating if scanning should continue or not.
 31    /// </summary>
 32    public bool ContinueRunning {
 833      get { return continueRunning_; }
 034      set { continueRunning_ = value; }
 35    }
 36
 37    #region Instance Fields
 38    string name_;
 439    bool continueRunning_ = true;
 40    #endregion
 41  }
 42
 43  /// <summary>
 44  /// Event arguments during processing of a single file or directory.
 45  /// </summary>
 46  public class ProgressEventArgs : EventArgs
 47  {
 48    #region Constructors
 49    /// <summary>
 50    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 51    /// </summary>
 52    /// <param name="name">The file or directory name if known.</param>
 53    /// <param name="processed">The number of bytes processed so far</param>
 54    /// <param name="target">The total number of bytes to process, 0 if not known</param>
 55    public ProgressEventArgs(string name, long processed, long target)
 56    {
 57      name_ = name;
 58      processed_ = processed;
 59      target_ = target;
 60    }
 61    #endregion
 62
 63    /// <summary>
 64    /// The name for this event if known.
 65    /// </summary>
 66    public string Name {
 67      get { return name_; }
 68    }
 69
 70    /// <summary>
 71    /// Get set a value indicating wether scanning should continue or not.
 72    /// </summary>
 73    public bool ContinueRunning {
 74      get { return continueRunning_; }
 75      set { continueRunning_ = value; }
 76    }
 77
 78    /// <summary>
 79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed
 80    /// </summary>
 81    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>
 82    public float PercentComplete {
 83      get {
 84        float result;
 85        if (target_ <= 0) {
 86          result = 0;
 87        } else {
 88          result = ((float)processed_ / (float)target_) * 100.0f;
 89        }
 90        return result;
 91      }
 92    }
 93
 94    /// <summary>
 95    /// The number of bytes processed so far
 96    /// </summary>
 97    public long Processed {
 98      get { return processed_; }
 99    }
 100
 101    /// <summary>
 102    /// The number of bytes to process.
 103    /// </summary>
 104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>
 105    public long Target {
 106      get { return target_; }
 107    }
 108
 109    #region Instance Fields
 110    string name_;
 111    long processed_;
 112    long target_;
 113    bool continueRunning_ = true;
 114    #endregion
 115  }
 116
 117  /// <summary>
 118  /// Event arguments for directories.
 119  /// </summary>
 120  public class DirectoryEventArgs : ScanEventArgs
 121  {
 122    #region Constructors
 123    /// <summary>
 124    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.
 125    /// </summary>
 126    /// <param name="name">The name for this directory.</param>
 127    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par
 128    public DirectoryEventArgs(string name, bool hasMatchingFiles)
 129      : base(name)
 130    {
 131      hasMatchingFiles_ = hasMatchingFiles;
 132    }
 133    #endregion
 134
 135    /// <summary>
 136    /// Get a value indicating if the directory contains any matching files or not.
 137    /// </summary>
 138    public bool HasMatchingFiles {
 139      get { return hasMatchingFiles_; }
 140    }
 141
 142    readonly
 143
 144    #region Instance Fields
 145    bool hasMatchingFiles_;
 146    #endregion
 147  }
 148
 149  /// <summary>
 150  /// Arguments passed when scan failures are detected.
 151  /// </summary>
 152  public class ScanFailureEventArgs : EventArgs
 153  {
 154    #region Constructors
 155    /// <summary>
 156    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>
 157    /// </summary>
 158    /// <param name="name">The name to apply.</param>
 159    /// <param name="e">The exception to use.</param>
 160    public ScanFailureEventArgs(string name, Exception e)
 161    {
 162      name_ = name;
 163      exception_ = e;
 164      continueRunning_ = true;
 165    }
 166    #endregion
 167
 168    /// <summary>
 169    /// The applicable name.
 170    /// </summary>
 171    public string Name {
 172      get { return name_; }
 173    }
 174
 175    /// <summary>
 176    /// The applicable exception.
 177    /// </summary>
 178    public Exception Exception {
 179      get { return exception_; }
 180    }
 181
 182    /// <summary>
 183    /// Get / set a value indicating wether scanning should continue.
 184    /// </summary>
 185    public bool ContinueRunning {
 186      get { return continueRunning_; }
 187      set { continueRunning_ = value; }
 188    }
 189
 190    #region Instance Fields
 191    string name_;
 192    Exception exception_;
 193    bool continueRunning_;
 194    #endregion
 195  }
 196
 197  #endregion
 198
 199  #region Delegates
 200  /// <summary>
 201  /// Delegate invoked before starting to process a file.
 202  /// </summary>
 203  /// <param name="sender">The source of the event</param>
 204  /// <param name="e">The event arguments.</param>
 205  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);
 206
 207  /// <summary>
 208  /// Delegate invoked during processing of a file or directory
 209  /// </summary>
 210  /// <param name="sender">The source of the event</param>
 211  /// <param name="e">The event arguments.</param>
 212  public delegate void ProgressHandler(object sender, ProgressEventArgs e);
 213
 214  /// <summary>
 215  /// Delegate invoked when a file has been completely processed.
 216  /// </summary>
 217  /// <param name="sender">The source of the event</param>
 218  /// <param name="e">The event arguments.</param>
 219  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);
 220
 221  /// <summary>
 222  /// Delegate invoked when a directory failure is detected.
 223  /// </summary>
 224  /// <param name="sender">The source of the event</param>
 225  /// <param name="e">The event arguments.</param>
 226  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);
 227
 228  /// <summary>
 229  /// Delegate invoked when a file failure is detected.
 230  /// </summary>
 231  /// <param name="sender">The source of the event</param>
 232  /// <param name="e">The event arguments.</param>
 233  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);
 234  #endregion
 235
 236  /// <summary>
 237  /// FileSystemScanner provides facilities scanning of files and directories.
 238  /// </summary>
 239  public class FileSystemScanner
 240  {
 241    #region Constructors
 242    /// <summary>
 243    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 244    /// </summary>
 245    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>
 246    public FileSystemScanner(string filter)
 247    {
 248      fileFilter_ = new PathFilter(filter);
 249    }
 250
 251    /// <summary>
 252    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 253    /// </summary>
 254    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
 255    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>
 256    public FileSystemScanner(string fileFilter, string directoryFilter)
 257    {
 258      fileFilter_ = new PathFilter(fileFilter);
 259      directoryFilter_ = new PathFilter(directoryFilter);
 260    }
 261
 262    /// <summary>
 263    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 264    /// </summary>
 265    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
 266    public FileSystemScanner(IScanFilter fileFilter)
 267    {
 268      fileFilter_ = fileFilter;
 269    }
 270
 271    /// <summary>
 272    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 273    /// </summary>
 274    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>
 275    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>
 276    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)
 277    {
 278      fileFilter_ = fileFilter;
 279      directoryFilter_ = directoryFilter;
 280    }
 281    #endregion
 282
 283    #region Delegates
 284    /// <summary>
 285    /// Delegate to invoke when a directory is processed.
 286    /// </summary>
 287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;
 288
 289    /// <summary>
 290    /// Delegate to invoke when a file is processed.
 291    /// </summary>
 292    public ProcessFileHandler ProcessFile;
 293
 294    /// <summary>
 295    /// Delegate to invoke when processing for a file has finished.
 296    /// </summary>
 297    public CompletedFileHandler CompletedFile;
 298
 299    /// <summary>
 300    /// Delegate to invoke when a directory failure is detected.
 301    /// </summary>
 302    public DirectoryFailureHandler DirectoryFailure;
 303
 304    /// <summary>
 305    /// Delegate to invoke when a file failure is detected.
 306    /// </summary>
 307    public FileFailureHandler FileFailure;
 308    #endregion
 309
 310    /// <summary>
 311    /// Raise the DirectoryFailure event.
 312    /// </summary>
 313    /// <param name="directory">The directory name.</param>
 314    /// <param name="e">The exception detected.</param>
 315    bool OnDirectoryFailure(string directory, Exception e)
 316    {
 317      DirectoryFailureHandler handler = DirectoryFailure;
 318      bool result = (handler != null);
 319      if (result) {
 320        var args = new ScanFailureEventArgs(directory, e);
 321        handler(this, args);
 322        alive_ = args.ContinueRunning;
 323      }
 324      return result;
 325    }
 326
 327    /// <summary>
 328    /// Raise the FileFailure event.
 329    /// </summary>
 330    /// <param name="file">The file name.</param>
 331    /// <param name="e">The exception detected.</param>
 332    bool OnFileFailure(string file, Exception e)
 333    {
 334      FileFailureHandler handler = FileFailure;
 335
 336      bool result = (handler != null);
 337
 338      if (result) {
 339        var args = new ScanFailureEventArgs(file, e);
 340        FileFailure(this, args);
 341        alive_ = args.ContinueRunning;
 342      }
 343      return result;
 344    }
 345
 346    /// <summary>
 347    /// Raise the ProcessFile event.
 348    /// </summary>
 349    /// <param name="file">The file name.</param>
 350    void OnProcessFile(string file)
 351    {
 352      ProcessFileHandler handler = ProcessFile;
 353
 354      if (handler != null) {
 355        var args = new ScanEventArgs(file);
 356        handler(this, args);
 357        alive_ = args.ContinueRunning;
 358      }
 359    }
 360
 361    /// <summary>
 362    /// Raise the complete file event
 363    /// </summary>
 364    /// <param name="file">The file name</param>
 365    void OnCompleteFile(string file)
 366    {
 367      CompletedFileHandler handler = CompletedFile;
 368
 369      if (handler != null) {
 370        var args = new ScanEventArgs(file);
 371        handler(this, args);
 372        alive_ = args.ContinueRunning;
 373      }
 374    }
 375
 376    /// <summary>
 377    /// Raise the ProcessDirectory event.
 378    /// </summary>
 379    /// <param name="directory">The directory name.</param>
 380    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>
 381    void OnProcessDirectory(string directory, bool hasMatchingFiles)
 382    {
 383      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;
 384
 385      if (handler != null) {
 386        var args = new DirectoryEventArgs(directory, hasMatchingFiles);
 387        handler(this, args);
 388        alive_ = args.ContinueRunning;
 389      }
 390    }
 391
 392    /// <summary>
 393    /// Scan a directory.
 394    /// </summary>
 395    /// <param name="directory">The base directory to scan.</param>
 396    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>
 397    public void Scan(string directory, bool recurse)
 398    {
 399      alive_ = true;
 400      ScanDir(directory, recurse);
 401    }
 402
 403    void ScanDir(string directory, bool recurse)
 404    {
 405
 406      try {
 407        string[] names = System.IO.Directory.GetFiles(directory);
 408        bool hasMatch = false;
 409        for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {
 410          if (!fileFilter_.IsMatch(names[fileIndex])) {
 411            names[fileIndex] = null;
 412          } else {
 413            hasMatch = true;
 414          }
 415        }
 416
 417        OnProcessDirectory(directory, hasMatch);
 418
 419        if (alive_ && hasMatch) {
 420          foreach (string fileName in names) {
 421            try {
 422              if (fileName != null) {
 423                OnProcessFile(fileName);
 424                if (!alive_) {
 425                  break;
 426                }
 427              }
 428            } catch (Exception e) {
 429              if (!OnFileFailure(fileName, e)) {
 430                throw;
 431              }
 432            }
 433          }
 434        }
 435      } catch (Exception e) {
 436        if (!OnDirectoryFailure(directory, e)) {
 437          throw;
 438        }
 439      }
 440
 441      if (alive_ && recurse) {
 442        try {
 443          string[] names = System.IO.Directory.GetDirectories(directory);
 444          foreach (string fulldir in names) {
 445            if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {
 446              ScanDir(fulldir, true);
 447              if (!alive_) {
 448                break;
 449              }
 450            }
 451          }
 452        } catch (Exception e) {
 453          if (!OnDirectoryFailure(directory, e)) {
 454            throw;
 455          }
 456        }
 457      }
 458    }
 459
 460    #region Instance Fields
 461    /// <summary>
 462    /// The file filter currently in use.
 463    /// </summary>
 464    IScanFilter fileFilter_;
 465    /// <summary>
 466    /// The directory filter currently in use.
 467    /// </summary>
 468    IScanFilter directoryFilter_;
 469    /// <summary>
 470    /// Flag indicating if scanning should continue running.
 471    /// </summary>
 472    bool alive_;
 473    #endregion
 474  }
 475}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ScanFailureEventArgs.htm b/docs/opencover/ICSharpCode.SharpZipLib_ScanFailureEventArgs.htm new file mode 100644 index 000000000..13ec860b5 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ScanFailureEventArgs.htm @@ -0,0 +1,516 @@ + + + + +ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs
Covered lines:0
Uncovered lines:9
Coverable lines:9
Total lines:475
Line coverage:0%
+

Metrics

+ + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\FileSystemScanner.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Core
 4{
 5  #region EventArgs
 6  /// <summary>
 7  /// Event arguments for scanning.
 8  /// </summary>
 9  public class ScanEventArgs : EventArgs
 10  {
 11    #region Constructors
 12    /// <summary>
 13    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 14    /// </summary>
 15    /// <param name="name">The file or directory name.</param>
 16    public ScanEventArgs(string name)
 17    {
 18      name_ = name;
 19    }
 20    #endregion
 21
 22    /// <summary>
 23    /// The file or directory name for this event.
 24    /// </summary>
 25    public string Name {
 26      get { return name_; }
 27    }
 28
 29    /// <summary>
 30    /// Get set a value indicating if scanning should continue or not.
 31    /// </summary>
 32    public bool ContinueRunning {
 33      get { return continueRunning_; }
 34      set { continueRunning_ = value; }
 35    }
 36
 37    #region Instance Fields
 38    string name_;
 39    bool continueRunning_ = true;
 40    #endregion
 41  }
 42
 43  /// <summary>
 44  /// Event arguments during processing of a single file or directory.
 45  /// </summary>
 46  public class ProgressEventArgs : EventArgs
 47  {
 48    #region Constructors
 49    /// <summary>
 50    /// Initialise a new instance of <see cref="ScanEventArgs"/>
 51    /// </summary>
 52    /// <param name="name">The file or directory name if known.</param>
 53    /// <param name="processed">The number of bytes processed so far</param>
 54    /// <param name="target">The total number of bytes to process, 0 if not known</param>
 55    public ProgressEventArgs(string name, long processed, long target)
 56    {
 57      name_ = name;
 58      processed_ = processed;
 59      target_ = target;
 60    }
 61    #endregion
 62
 63    /// <summary>
 64    /// The name for this event if known.
 65    /// </summary>
 66    public string Name {
 67      get { return name_; }
 68    }
 69
 70    /// <summary>
 71    /// Get set a value indicating wether scanning should continue or not.
 72    /// </summary>
 73    public bool ContinueRunning {
 74      get { return continueRunning_; }
 75      set { continueRunning_ = value; }
 76    }
 77
 78    /// <summary>
 79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed
 80    /// </summary>
 81    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>
 82    public float PercentComplete {
 83      get {
 84        float result;
 85        if (target_ <= 0) {
 86          result = 0;
 87        } else {
 88          result = ((float)processed_ / (float)target_) * 100.0f;
 89        }
 90        return result;
 91      }
 92    }
 93
 94    /// <summary>
 95    /// The number of bytes processed so far
 96    /// </summary>
 97    public long Processed {
 98      get { return processed_; }
 99    }
 100
 101    /// <summary>
 102    /// The number of bytes to process.
 103    /// </summary>
 104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>
 105    public long Target {
 106      get { return target_; }
 107    }
 108
 109    #region Instance Fields
 110    string name_;
 111    long processed_;
 112    long target_;
 113    bool continueRunning_ = true;
 114    #endregion
 115  }
 116
 117  /// <summary>
 118  /// Event arguments for directories.
 119  /// </summary>
 120  public class DirectoryEventArgs : ScanEventArgs
 121  {
 122    #region Constructors
 123    /// <summary>
 124    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.
 125    /// </summary>
 126    /// <param name="name">The name for this directory.</param>
 127    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par
 128    public DirectoryEventArgs(string name, bool hasMatchingFiles)
 129      : base(name)
 130    {
 131      hasMatchingFiles_ = hasMatchingFiles;
 132    }
 133    #endregion
 134
 135    /// <summary>
 136    /// Get a value indicating if the directory contains any matching files or not.
 137    /// </summary>
 138    public bool HasMatchingFiles {
 139      get { return hasMatchingFiles_; }
 140    }
 141
 142    readonly
 143
 144    #region Instance Fields
 145    bool hasMatchingFiles_;
 146    #endregion
 147  }
 148
 149  /// <summary>
 150  /// Arguments passed when scan failures are detected.
 151  /// </summary>
 152  public class ScanFailureEventArgs : EventArgs
 153  {
 154    #region Constructors
 155    /// <summary>
 156    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>
 157    /// </summary>
 158    /// <param name="name">The name to apply.</param>
 159    /// <param name="e">The exception to use.</param>
 0160    public ScanFailureEventArgs(string name, Exception e)
 161    {
 0162      name_ = name;
 0163      exception_ = e;
 0164      continueRunning_ = true;
 0165    }
 166    #endregion
 167
 168    /// <summary>
 169    /// The applicable name.
 170    /// </summary>
 171    public string Name {
 0172      get { return name_; }
 173    }
 174
 175    /// <summary>
 176    /// The applicable exception.
 177    /// </summary>
 178    public Exception Exception {
 0179      get { return exception_; }
 180    }
 181
 182    /// <summary>
 183    /// Get / set a value indicating wether scanning should continue.
 184    /// </summary>
 185    public bool ContinueRunning {
 0186      get { return continueRunning_; }
 0187      set { continueRunning_ = value; }
 188    }
 189
 190    #region Instance Fields
 191    string name_;
 192    Exception exception_;
 193    bool continueRunning_;
 194    #endregion
 195  }
 196
 197  #endregion
 198
 199  #region Delegates
 200  /// <summary>
 201  /// Delegate invoked before starting to process a file.
 202  /// </summary>
 203  /// <param name="sender">The source of the event</param>
 204  /// <param name="e">The event arguments.</param>
 205  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);
 206
 207  /// <summary>
 208  /// Delegate invoked during processing of a file or directory
 209  /// </summary>
 210  /// <param name="sender">The source of the event</param>
 211  /// <param name="e">The event arguments.</param>
 212  public delegate void ProgressHandler(object sender, ProgressEventArgs e);
 213
 214  /// <summary>
 215  /// Delegate invoked when a file has been completely processed.
 216  /// </summary>
 217  /// <param name="sender">The source of the event</param>
 218  /// <param name="e">The event arguments.</param>
 219  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);
 220
 221  /// <summary>
 222  /// Delegate invoked when a directory failure is detected.
 223  /// </summary>
 224  /// <param name="sender">The source of the event</param>
 225  /// <param name="e">The event arguments.</param>
 226  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);
 227
 228  /// <summary>
 229  /// Delegate invoked when a file failure is detected.
 230  /// </summary>
 231  /// <param name="sender">The source of the event</param>
 232  /// <param name="e">The event arguments.</param>
 233  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);
 234  #endregion
 235
 236  /// <summary>
 237  /// FileSystemScanner provides facilities scanning of files and directories.
 238  /// </summary>
 239  public class FileSystemScanner
 240  {
 241    #region Constructors
 242    /// <summary>
 243    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 244    /// </summary>
 245    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>
 246    public FileSystemScanner(string filter)
 247    {
 248      fileFilter_ = new PathFilter(filter);
 249    }
 250
 251    /// <summary>
 252    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 253    /// </summary>
 254    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
 255    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>
 256    public FileSystemScanner(string fileFilter, string directoryFilter)
 257    {
 258      fileFilter_ = new PathFilter(fileFilter);
 259      directoryFilter_ = new PathFilter(directoryFilter);
 260    }
 261
 262    /// <summary>
 263    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 264    /// </summary>
 265    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
 266    public FileSystemScanner(IScanFilter fileFilter)
 267    {
 268      fileFilter_ = fileFilter;
 269    }
 270
 271    /// <summary>
 272    /// Initialise a new instance of <see cref="FileSystemScanner"></see>
 273    /// </summary>
 274    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>
 275    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>
 276    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)
 277    {
 278      fileFilter_ = fileFilter;
 279      directoryFilter_ = directoryFilter;
 280    }
 281    #endregion
 282
 283    #region Delegates
 284    /// <summary>
 285    /// Delegate to invoke when a directory is processed.
 286    /// </summary>
 287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;
 288
 289    /// <summary>
 290    /// Delegate to invoke when a file is processed.
 291    /// </summary>
 292    public ProcessFileHandler ProcessFile;
 293
 294    /// <summary>
 295    /// Delegate to invoke when processing for a file has finished.
 296    /// </summary>
 297    public CompletedFileHandler CompletedFile;
 298
 299    /// <summary>
 300    /// Delegate to invoke when a directory failure is detected.
 301    /// </summary>
 302    public DirectoryFailureHandler DirectoryFailure;
 303
 304    /// <summary>
 305    /// Delegate to invoke when a file failure is detected.
 306    /// </summary>
 307    public FileFailureHandler FileFailure;
 308    #endregion
 309
 310    /// <summary>
 311    /// Raise the DirectoryFailure event.
 312    /// </summary>
 313    /// <param name="directory">The directory name.</param>
 314    /// <param name="e">The exception detected.</param>
 315    bool OnDirectoryFailure(string directory, Exception e)
 316    {
 317      DirectoryFailureHandler handler = DirectoryFailure;
 318      bool result = (handler != null);
 319      if (result) {
 320        var args = new ScanFailureEventArgs(directory, e);
 321        handler(this, args);
 322        alive_ = args.ContinueRunning;
 323      }
 324      return result;
 325    }
 326
 327    /// <summary>
 328    /// Raise the FileFailure event.
 329    /// </summary>
 330    /// <param name="file">The file name.</param>
 331    /// <param name="e">The exception detected.</param>
 332    bool OnFileFailure(string file, Exception e)
 333    {
 334      FileFailureHandler handler = FileFailure;
 335
 336      bool result = (handler != null);
 337
 338      if (result) {
 339        var args = new ScanFailureEventArgs(file, e);
 340        FileFailure(this, args);
 341        alive_ = args.ContinueRunning;
 342      }
 343      return result;
 344    }
 345
 346    /// <summary>
 347    /// Raise the ProcessFile event.
 348    /// </summary>
 349    /// <param name="file">The file name.</param>
 350    void OnProcessFile(string file)
 351    {
 352      ProcessFileHandler handler = ProcessFile;
 353
 354      if (handler != null) {
 355        var args = new ScanEventArgs(file);
 356        handler(this, args);
 357        alive_ = args.ContinueRunning;
 358      }
 359    }
 360
 361    /// <summary>
 362    /// Raise the complete file event
 363    /// </summary>
 364    /// <param name="file">The file name</param>
 365    void OnCompleteFile(string file)
 366    {
 367      CompletedFileHandler handler = CompletedFile;
 368
 369      if (handler != null) {
 370        var args = new ScanEventArgs(file);
 371        handler(this, args);
 372        alive_ = args.ContinueRunning;
 373      }
 374    }
 375
 376    /// <summary>
 377    /// Raise the ProcessDirectory event.
 378    /// </summary>
 379    /// <param name="directory">The directory name.</param>
 380    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>
 381    void OnProcessDirectory(string directory, bool hasMatchingFiles)
 382    {
 383      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;
 384
 385      if (handler != null) {
 386        var args = new DirectoryEventArgs(directory, hasMatchingFiles);
 387        handler(this, args);
 388        alive_ = args.ContinueRunning;
 389      }
 390    }
 391
 392    /// <summary>
 393    /// Scan a directory.
 394    /// </summary>
 395    /// <param name="directory">The base directory to scan.</param>
 396    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>
 397    public void Scan(string directory, bool recurse)
 398    {
 399      alive_ = true;
 400      ScanDir(directory, recurse);
 401    }
 402
 403    void ScanDir(string directory, bool recurse)
 404    {
 405
 406      try {
 407        string[] names = System.IO.Directory.GetFiles(directory);
 408        bool hasMatch = false;
 409        for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {
 410          if (!fileFilter_.IsMatch(names[fileIndex])) {
 411            names[fileIndex] = null;
 412          } else {
 413            hasMatch = true;
 414          }
 415        }
 416
 417        OnProcessDirectory(directory, hasMatch);
 418
 419        if (alive_ && hasMatch) {
 420          foreach (string fileName in names) {
 421            try {
 422              if (fileName != null) {
 423                OnProcessFile(fileName);
 424                if (!alive_) {
 425                  break;
 426                }
 427              }
 428            } catch (Exception e) {
 429              if (!OnFileFailure(fileName, e)) {
 430                throw;
 431              }
 432            }
 433          }
 434        }
 435      } catch (Exception e) {
 436        if (!OnDirectoryFailure(directory, e)) {
 437          throw;
 438        }
 439      }
 440
 441      if (alive_ && recurse) {
 442        try {
 443          string[] names = System.IO.Directory.GetDirectories(directory);
 444          foreach (string fulldir in names) {
 445            if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {
 446              ScanDir(fulldir, true);
 447              if (!alive_) {
 448                break;
 449              }
 450            }
 451          }
 452        } catch (Exception e) {
 453          if (!OnDirectoryFailure(directory, e)) {
 454            throw;
 455          }
 456        }
 457      }
 458    }
 459
 460    #region Instance Fields
 461    /// <summary>
 462    /// The file filter currently in use.
 463    /// </summary>
 464    IScanFilter fileFilter_;
 465    /// <summary>
 466    /// The directory filter currently in use.
 467    /// </summary>
 468    IScanFilter directoryFilter_;
 469    /// <summary>
 470    /// Flag indicating if scanning should continue running.
 471    /// </summary>
 472    bool alive_;
 473    #endregion
 474  }
 475}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_SharpZipBaseException.htm b/docs/opencover/ICSharpCode.SharpZipLib_SharpZipBaseException.htm new file mode 100644 index 000000000..986d556ce --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_SharpZipBaseException.htm @@ -0,0 +1,96 @@ + + + + +ICSharpCode.SharpZipLib.SharpZipBaseException - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.SharpZipBaseException
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\SharpZipBaseException.cs
Covered lines:2
Uncovered lines:6
Coverable lines:8
Total lines:52
Line coverage:25%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor()100
.ctor(...)1100100
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\SharpZipBaseException.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Runtime.Serialization;
 3
 4namespace ICSharpCode.SharpZipLib
 5{
 6  /// <summary>
 7  /// SharpZipBaseException is the base exception class for SharpZipLib.
 8  /// All library exceptions are derived from this.
 9  /// </summary>
 10  /// <remarks>NOTE: Not all exceptions thrown will be derived from this class.
 11  /// A variety of other exceptions are possible for example <see cref="ArgumentNullException"></see></remarks>
 12  [Serializable]
 13  public class SharpZipBaseException : Exception
 14  {
 15    /// <summary>
 16    /// Deserialization constructor
 17    /// </summary>
 18    /// <param name="info"><see cref="System.Runtime.Serialization.SerializationInfo"/> for this constructor</param>
 19    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
 20    protected SharpZipBaseException(SerializationInfo info, StreamingContext context)
 021      : base(info, context)
 22    {
 023    }
 24
 25    /// <summary>
 26    /// Initializes a new instance of the SharpZipBaseException class.
 27    /// </summary>
 028    public SharpZipBaseException()
 29    {
 030    }
 31
 32    /// <summary>
 33    /// Initializes a new instance of the SharpZipBaseException class with a specified error message.
 34    /// </summary>
 35    /// <param name="message">A message describing the exception.</param>
 36    public SharpZipBaseException(string message)
 1537      : base(message)
 38    {
 1539    }
 40
 41    /// <summary>
 42    /// Initializes a new instance of the SharpZipBaseException class with a specified
 43    /// error message and a reference to the inner exception that is the cause of this exception.
 44    /// </summary>
 45    /// <param name="message">A message describing the exception.</param>
 46    /// <param name="innerException">The inner exception</param>
 47    public SharpZipBaseException(string message, Exception innerException)
 048      : base(message, innerException)
 49    {
 050    }
 51  }
 52}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_StaticDiskDataSource.htm b/docs/opencover/ICSharpCode.SharpZipLib_StaticDiskDataSource.htm new file mode 100644 index 000000000..dfb94ee0c --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_StaticDiskDataSource.htm @@ -0,0 +1,4305 @@ + + + + +ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs
Covered lines:0
Uncovered lines:4
Coverable lines:4
Total lines:4263
Line coverage:0%
+

Metrics

+ + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
GetSource()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.IO;
 4using System.Text;
 5using System.Globalization;
 6using System.Security.Cryptography;
 7using ICSharpCode.SharpZipLib.Encryption;
 8using ICSharpCode.SharpZipLib.Core;
 9using ICSharpCode.SharpZipLib.Checksum;
 10using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 11using ICSharpCode.SharpZipLib.Zip.Compression;
 12
 13namespace ICSharpCode.SharpZipLib.Zip
 14{
 15  #region Keys Required Event Args
 16  /// <summary>
 17  /// Arguments used with KeysRequiredEvent
 18  /// </summary>
 19  public class KeysRequiredEventArgs : EventArgs
 20  {
 21    #region Constructors
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 24    /// </summary>
 25    /// <param name="name">The name of the file for which keys are required.</param>
 26    public KeysRequiredEventArgs(string name)
 27    {
 28      fileName = name;
 29    }
 30
 31    /// <summary>
 32    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 33    /// </summary>
 34    /// <param name="name">The name of the file for which keys are required.</param>
 35    /// <param name="keyValue">The current key value.</param>
 36    public KeysRequiredEventArgs(string name, byte[] keyValue)
 37    {
 38      fileName = name;
 39      key = keyValue;
 40    }
 41
 42    #endregion
 43    #region Properties
 44    /// <summary>
 45    /// Gets the name of the file for which keys are required.
 46    /// </summary>
 47    public string FileName {
 48      get { return fileName; }
 49    }
 50
 51    /// <summary>
 52    /// Gets or sets the key value
 53    /// </summary>
 54    public byte[] Key {
 55      get { return key; }
 56      set { key = value; }
 57    }
 58    #endregion
 59
 60    #region Instance Fields
 61    string fileName;
 62    byte[] key;
 63    #endregion
 64  }
 65  #endregion
 66
 67  #region Test Definitions
 68  /// <summary>
 69  /// The strategy to apply to testing.
 70  /// </summary>
 71  public enum TestStrategy
 72  {
 73    /// <summary>
 74    /// Find the first error only.
 75    /// </summary>
 76    FindFirstError,
 77    /// <summary>
 78    /// Find all possible errors.
 79    /// </summary>
 80    FindAllErrors,
 81  }
 82
 83  /// <summary>
 84  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.
 85  /// </summary>
 86  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 87  public enum TestOperation
 88  {
 89    /// <summary>
 90    /// Setting up testing.
 91    /// </summary>
 92    Initialising,
 93
 94    /// <summary>
 95    /// Testing an individual entries header
 96    /// </summary>
 97    EntryHeader,
 98
 99    /// <summary>
 100    /// Testing an individual entries data
 101    /// </summary>
 102    EntryData,
 103
 104    /// <summary>
 105    /// Testing an individual entry has completed.
 106    /// </summary>
 107    EntryComplete,
 108
 109    /// <summary>
 110    /// Running miscellaneous tests
 111    /// </summary>
 112    MiscellaneousTests,
 113
 114    /// <summary>
 115    /// Testing is complete
 116    /// </summary>
 117    Complete,
 118  }
 119
 120  /// <summary>
 121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.
 122  /// </summary>
 123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 124  public class TestStatus
 125  {
 126    #region Constructors
 127    /// <summary>
 128    /// Initialise a new instance of <see cref="TestStatus"/>
 129    /// </summary>
 130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>
 131    public TestStatus(ZipFile file)
 132    {
 133      file_ = file;
 134    }
 135    #endregion
 136
 137    #region Properties
 138
 139    /// <summary>
 140    /// Get the current <see cref="TestOperation"/> in progress.
 141    /// </summary>
 142    public TestOperation Operation {
 143      get { return operation_; }
 144    }
 145
 146    /// <summary>
 147    /// Get the <see cref="ZipFile"/> this status is applicable to.
 148    /// </summary>
 149    public ZipFile File {
 150      get { return file_; }
 151    }
 152
 153    /// <summary>
 154    /// Get the current/last entry tested.
 155    /// </summary>
 156    public ZipEntry Entry {
 157      get { return entry_; }
 158    }
 159
 160    /// <summary>
 161    /// Get the number of errors detected so far.
 162    /// </summary>
 163    public int ErrorCount {
 164      get { return errorCount_; }
 165    }
 166
 167    /// <summary>
 168    /// Get the number of bytes tested so far for the current entry.
 169    /// </summary>
 170    public long BytesTested {
 171      get { return bytesTested_; }
 172    }
 173
 174    /// <summary>
 175    /// Get a value indicating wether the last entry test was valid.
 176    /// </summary>
 177    public bool EntryValid {
 178      get { return entryValid_; }
 179    }
 180    #endregion
 181
 182    #region Internal API
 183    internal void AddError()
 184    {
 185      errorCount_++;
 186      entryValid_ = false;
 187    }
 188
 189    internal void SetOperation(TestOperation operation)
 190    {
 191      operation_ = operation;
 192    }
 193
 194    internal void SetEntry(ZipEntry entry)
 195    {
 196      entry_ = entry;
 197      entryValid_ = true;
 198      bytesTested_ = 0;
 199    }
 200
 201    internal void SetBytesTested(long value)
 202    {
 203      bytesTested_ = value;
 204    }
 205    #endregion
 206
 207    #region Instance Fields
 208    ZipFile file_;
 209    ZipEntry entry_;
 210    bool entryValid_;
 211    int errorCount_;
 212    long bytesTested_;
 213    TestOperation operation_;
 214    #endregion
 215  }
 216
 217  /// <summary>
 218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if
 219  /// </summary>
 220  /// <remarks>If the message is non-null an error has occured.  If the message is null
 221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>
 222  public delegate void ZipTestResultHandler(TestStatus status, string message);
 223  #endregion
 224
 225  #region Update Definitions
 226  /// <summary>
 227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.
 228  /// </summary>
 229  public enum FileUpdateMode
 230  {
 231    /// <summary>
 232    /// Perform all updates on temporary files ensuring that the original file is saved.
 233    /// </summary>
 234    Safe,
 235    /// <summary>
 236    /// Update the archive directly, which is faster but less safe.
 237    /// </summary>
 238    Direct,
 239  }
 240  #endregion
 241
 242  #region ZipFile Class
 243  /// <summary>
 244  /// This class represents a Zip archive.  You can ask for the contained
 245  /// entries, or get an input stream for a file entry.  The entry is
 246  /// automatically decompressed.
 247  ///
 248  /// You can also update the archive adding or deleting entries.
 249  ///
 250  /// This class is thread safe for input:  You can open input streams for arbitrary
 251  /// entries in different threads.
 252  /// <br/>
 253  /// <br/>Author of the original java version : Jochen Hoenicke
 254  /// </summary>
 255  /// <example>
 256  /// <code>
 257  /// using System;
 258  /// using System.Text;
 259  /// using System.Collections;
 260  /// using System.IO;
 261  ///
 262  /// using ICSharpCode.SharpZipLib.Zip;
 263  ///
 264  /// class MainClass
 265  /// {
 266  ///   static public void Main(string[] args)
 267  ///   {
 268  ///     using (ZipFile zFile = new ZipFile(args[0])) {
 269  ///       Console.WriteLine("Listing of : " + zFile.Name);
 270  ///       Console.WriteLine("");
 271  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");
 272  ///       Console.WriteLine("--------  --------  --------  ------  ---------");
 273  ///       foreach (ZipEntry e in zFile) {
 274  ///         if ( e.IsFile ) {
 275  ///           DateTime d = e.DateTime;
 276  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,
 277  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),
 278  ///             e.Name);
 279  ///         }
 280  ///       }
 281  ///     }
 282  ///   }
 283  /// }
 284  /// </code>
 285  /// </example>
 286  public class ZipFile : IEnumerable, IDisposable
 287  {
 288    #region KeyHandling
 289
 290    /// <summary>
 291    /// Delegate for handling keys/password setting during compresion/decompression.
 292    /// </summary>
 293    public delegate void KeysRequiredEventHandler(
 294      object sender,
 295      KeysRequiredEventArgs e
 296    );
 297
 298    /// <summary>
 299    /// Event handler for handling encryption keys.
 300    /// </summary>
 301    public KeysRequiredEventHandler KeysRequired;
 302
 303    /// <summary>
 304    /// Handles getting of encryption keys when required.
 305    /// </summary>
 306    /// <param name="fileName">The file for which encryption keys are required.</param>
 307    void OnKeysRequired(string fileName)
 308    {
 309      if (KeysRequired != null) {
 310        var krea = new KeysRequiredEventArgs(fileName, key);
 311        KeysRequired(this, krea);
 312        key = krea.Key;
 313      }
 314    }
 315
 316    /// <summary>
 317    /// Get/set the encryption key value.
 318    /// </summary>
 319    byte[] Key {
 320      get { return key; }
 321      set { key = value; }
 322    }
 323
 324    /// <summary>
 325    /// Password to be used for encrypting/decrypting files.
 326    /// </summary>
 327    /// <remarks>Set to null if no password is required.</remarks>
 328    public string Password {
 329      set {
 330        if (string.IsNullOrEmpty(value)) {
 331          key = null;
 332        } else {
 333          rawPassword_ = value;
 334          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));
 335        }
 336      }
 337    }
 338
 339    /// <summary>
 340    /// Get a value indicating wether encryption keys are currently available.
 341    /// </summary>
 342    bool HaveKeys {
 343      get { return key != null; }
 344    }
 345    #endregion
 346
 347    #region Constructors
 348    /// <summary>
 349    /// Opens a Zip file with the given name for reading.
 350    /// </summary>
 351    /// <param name="name">The name of the file to open.</param>
 352    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>
 353    /// <exception cref="IOException">
 354    /// An i/o error occurs
 355    /// </exception>
 356    /// <exception cref="ZipException">
 357    /// The file doesn't contain a valid zip archive.
 358    /// </exception>
 359    public ZipFile(string name)
 360    {
 361      if (name == null) {
 362        throw new ArgumentNullException(nameof(name));
 363      }
 364
 365      name_ = name;
 366
 367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 368      isStreamOwner = true;
 369
 370      try {
 371        ReadEntries();
 372      } catch {
 373        DisposeInternal(true);
 374        throw;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Opens a Zip file reading the given <see cref="FileStream"/>.
 380    /// </summary>
 381    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>
 382    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>
 383    /// <exception cref="IOException">
 384    /// An i/o error occurs.
 385    /// </exception>
 386    /// <exception cref="ZipException">
 387    /// The file doesn't contain a valid zip archive.
 388    /// </exception>
 389    public ZipFile(FileStream file)
 390    {
 391      if (file == null) {
 392        throw new ArgumentNullException(nameof(file));
 393      }
 394
 395      if (!file.CanSeek) {
 396        throw new ArgumentException("Stream is not seekable", nameof(file));
 397      }
 398
 399      baseStream_ = file;
 400      name_ = file.Name;
 401      isStreamOwner = true;
 402
 403      try {
 404        ReadEntries();
 405      } catch {
 406        DisposeInternal(true);
 407        throw;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Opens a Zip file reading the given <see cref="Stream"/>.
 413    /// </summary>
 414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
 415    /// <exception cref="IOException">
 416    /// An i/o error occurs
 417    /// </exception>
 418    /// <exception cref="ZipException">
 419    /// The stream doesn't contain a valid zip archive.<br/>
 420    /// </exception>
 421    /// <exception cref="ArgumentException">
 422    /// The <see cref="Stream">stream</see> doesnt support seeking.
 423    /// </exception>
 424    /// <exception cref="ArgumentNullException">
 425    /// The <see cref="Stream">stream</see> argument is null.
 426    /// </exception>
 427    public ZipFile(Stream stream)
 428    {
 429      if (stream == null) {
 430        throw new ArgumentNullException(nameof(stream));
 431      }
 432
 433      if (!stream.CanSeek) {
 434        throw new ArgumentException("Stream is not seekable", nameof(stream));
 435      }
 436
 437      baseStream_ = stream;
 438      isStreamOwner = true;
 439
 440      if (baseStream_.Length > 0) {
 441        try {
 442          ReadEntries();
 443        } catch {
 444          DisposeInternal(true);
 445          throw;
 446        }
 447      } else {
 448        entries_ = new ZipEntry[0];
 449        isNewArchive_ = true;
 450      }
 451    }
 452
 453    /// <summary>
 454    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
 455    /// </summary>
 456    internal ZipFile()
 457    {
 458      entries_ = new ZipEntry[0];
 459      isNewArchive_ = true;
 460    }
 461
 462    #endregion
 463
 464    #region Destructors and Closing
 465    /// <summary>
 466    /// Finalize this instance.
 467    /// </summary>
 468    ~ZipFile()
 469    {
 470      Dispose(false);
 471    }
 472
 473    /// <summary>
 474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying
 475    /// Once closed, no further instance methods should be called.
 476    /// </summary>
 477    /// <exception cref="System.IO.IOException">
 478    /// An i/o error occurs.
 479    /// </exception>
 480    public void Close()
 481    {
 482      DisposeInternal(true);
 483      GC.SuppressFinalize(this);
 484    }
 485
 486    #endregion
 487
 488    #region Creators
 489    /// <summary>
 490    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.
 491    /// </summary>
 492    /// <param name="fileName">The name of the archive to create.</param>
 493    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 494    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>
 495    public static ZipFile Create(string fileName)
 496    {
 497      if (fileName == null) {
 498        throw new ArgumentNullException(nameof(fileName));
 499      }
 500
 501      FileStream fs = File.Create(fileName);
 502
 503      var result = new ZipFile();
 504      result.name_ = fileName;
 505      result.baseStream_ = fs;
 506      result.isStreamOwner = true;
 507      return result;
 508    }
 509
 510    /// <summary>
 511    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.
 512    /// </summary>
 513    /// <param name="outStream">The stream providing data storage.</param>
 514    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 515    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>
 516    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>
 517    public static ZipFile Create(Stream outStream)
 518    {
 519      if (outStream == null) {
 520        throw new ArgumentNullException(nameof(outStream));
 521      }
 522
 523      if (!outStream.CanWrite) {
 524        throw new ArgumentException("Stream is not writeable", nameof(outStream));
 525      }
 526
 527      if (!outStream.CanSeek) {
 528        throw new ArgumentException("Stream is not seekable", nameof(outStream));
 529      }
 530
 531      var result = new ZipFile();
 532      result.baseStream_ = outStream;
 533      return result;
 534    }
 535
 536    #endregion
 537
 538    #region Properties
 539    /// <summary>
 540    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
 541    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
 542    /// </summary>
 543    /// <remarks>
 544    /// The default value is true in all cases.
 545    /// </remarks>
 546    public bool IsStreamOwner {
 547      get { return isStreamOwner; }
 548      set { isStreamOwner = value; }
 549    }
 550
 551    /// <summary>
 552    /// Get a value indicating wether
 553    /// this archive is embedded in another file or not.
 554    /// </summary>
 555    public bool IsEmbeddedArchive {
 556      // Not strictly correct in all circumstances currently
 557      get { return offsetOfFirstEntry > 0; }
 558    }
 559
 560    /// <summary>
 561    /// Get a value indicating that this archive is a new one.
 562    /// </summary>
 563    public bool IsNewArchive {
 564      get { return isNewArchive_; }
 565    }
 566
 567    /// <summary>
 568    /// Gets the comment for the zip file.
 569    /// </summary>
 570    public string ZipFileComment {
 571      get { return comment_; }
 572    }
 573
 574    /// <summary>
 575    /// Gets the name of this zip file.
 576    /// </summary>
 577    public string Name {
 578      get { return name_; }
 579    }
 580
 581    /// <summary>
 582    /// Gets the number of entries in this zip file.
 583    /// </summary>
 584    /// <exception cref="InvalidOperationException">
 585    /// The Zip file has been closed.
 586    /// </exception>
 587    [Obsolete("Use the Count property instead")]
 588    public int Size {
 589      get {
 590        return entries_.Length;
 591      }
 592    }
 593
 594    /// <summary>
 595    /// Get the number of entries contained in this <see cref="ZipFile"/>.
 596    /// </summary>
 597    public long Count {
 598      get {
 599        return entries_.Length;
 600      }
 601    }
 602
 603    /// <summary>
 604    /// Indexer property for ZipEntries
 605    /// </summary>
 606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
 607    public ZipEntry this[int index] {
 608      get {
 609        return (ZipEntry)entries_[index].Clone();
 610      }
 611    }
 612
 613    #endregion
 614
 615    #region Input Handling
 616    /// <summary>
 617    /// Gets an enumerator for the Zip entries in this Zip file.
 618    /// </summary>
 619    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>
 620    /// <exception cref="ObjectDisposedException">
 621    /// The Zip file has been closed.
 622    /// </exception>
 623    public IEnumerator GetEnumerator()
 624    {
 625      if (isDisposed_) {
 626        throw new ObjectDisposedException("ZipFile");
 627      }
 628
 629      return new ZipEntryEnumerator(entries_);
 630    }
 631
 632    /// <summary>
 633    /// Return the index of the entry with a matching name
 634    /// </summary>
 635    /// <param name="name">Entry name to find</param>
 636    /// <param name="ignoreCase">If true the comparison is case insensitive</param>
 637    /// <returns>The index position of the matching entry or -1 if not found</returns>
 638    /// <exception cref="ObjectDisposedException">
 639    /// The Zip file has been closed.
 640    /// </exception>
 641    public int FindEntry(string name, bool ignoreCase)
 642    {
 643      if (isDisposed_) {
 644        throw new ObjectDisposedException("ZipFile");
 645      }
 646
 647      // TODO: This will be slow as the next ice age for huge archives!
 648      for (int i = 0; i < entries_.Length; i++) {
 649        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {
 650          return i;
 651        }
 652      }
 653      return -1;
 654    }
 655
 656    /// <summary>
 657    /// Searches for a zip entry in this archive with the given name.
 658    /// String comparisons are case insensitive
 659    /// </summary>
 660    /// <param name="name">
 661    /// The name to find. May contain directory components separated by slashes ('/').
 662    /// </param>
 663    /// <returns>
 664    /// A clone of the zip entry, or null if no entry with that name exists.
 665    /// </returns>
 666    /// <exception cref="ObjectDisposedException">
 667    /// The Zip file has been closed.
 668    /// </exception>
 669    public ZipEntry GetEntry(string name)
 670    {
 671      if (isDisposed_) {
 672        throw new ObjectDisposedException("ZipFile");
 673      }
 674
 675      int index = FindEntry(name, true);
 676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;
 677    }
 678
 679    /// <summary>
 680    /// Gets an input stream for reading the given zip entry data in an uncompressed form.
 681    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
 682    /// </summary>
 683    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
 684    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
 685    /// <exception cref="ObjectDisposedException">
 686    /// The ZipFile has already been closed
 687    /// </exception>
 688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 689    /// The compression method for the entry is unknown
 690    /// </exception>
 691    /// <exception cref="IndexOutOfRangeException">
 692    /// The entry is not found in the ZipFile
 693    /// </exception>
 694    public Stream GetInputStream(ZipEntry entry)
 695    {
 696      if (entry == null) {
 697        throw new ArgumentNullException(nameof(entry));
 698      }
 699
 700      if (isDisposed_) {
 701        throw new ObjectDisposedException("ZipFile");
 702      }
 703
 704      long index = entry.ZipFileIndex;
 705      if ((index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name)) {
 706        index = FindEntry(entry.Name, true);
 707        if (index < 0) {
 708          throw new ZipException("Entry cannot be found");
 709        }
 710      }
 711      return GetInputStream(index);
 712    }
 713
 714    /// <summary>
 715    /// Creates an input stream reading a zip entry
 716    /// </summary>
 717    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
 718    /// <returns>
 719    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>
 720    /// </returns>
 721    /// <exception cref="ObjectDisposedException">
 722    /// The ZipFile has already been closed
 723    /// </exception>
 724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 725    /// The compression method for the entry is unknown
 726    /// </exception>
 727    /// <exception cref="IndexOutOfRangeException">
 728    /// The entry is not found in the ZipFile
 729    /// </exception>
 730    public Stream GetInputStream(long entryIndex)
 731    {
 732      if (isDisposed_) {
 733        throw new ObjectDisposedException("ZipFile");
 734      }
 735
 736      long start = LocateEntry(entries_[entryIndex]);
 737      CompressionMethod method = entries_[entryIndex].CompressionMethod;
 738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);
 739
 740      if (entries_[entryIndex].IsCrypted == true) {
 741        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);
 742        if (result == null) {
 743          throw new ZipException("Unable to decrypt this entry");
 744        }
 745      }
 746
 747      switch (method) {
 748        case CompressionMethod.Stored:
 749          // read as is.
 750          break;
 751
 752        case CompressionMethod.Deflated:
 753          // No need to worry about ownership and closing as underlying stream close does nothing.
 754          result = new InflaterInputStream(result, new Inflater(true));
 755          break;
 756
 757        default:
 758          throw new ZipException("Unsupported compression method " + method);
 759      }
 760
 761      return result;
 762    }
 763
 764    #endregion
 765
 766    #region Archive Testing
 767    /// <summary>
 768    /// Test an archive for integrity/validity
 769    /// </summary>
 770    /// <param name="testData">Perform low level data Crc check</param>
 771    /// <returns>true if all tests pass, false otherwise</returns>
 772    /// <remarks>Testing will terminate on the first error found.</remarks>
 773    public bool TestArchive(bool testData)
 774    {
 775      return TestArchive(testData, TestStrategy.FindFirstError, null);
 776    }
 777
 778    /// <summary>
 779    /// Test an archive for integrity/validity
 780    /// </summary>
 781    /// <param name="testData">Perform low level data Crc check</param>
 782    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
 783    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
 784    /// <returns>true if all tests pass, false otherwise</returns>
 785    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>
 786    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
 787    {
 788      if (isDisposed_) {
 789        throw new ObjectDisposedException("ZipFile");
 790      }
 791
 792      var status = new TestStatus(this);
 793
 794      if (resultHandler != null) {
 795        resultHandler(status, null);
 796      }
 797
 798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;
 799
 800      bool testing = true;
 801
 802      try {
 803        int entryIndex = 0;
 804
 805        while (testing && (entryIndex < Count)) {
 806          if (resultHandler != null) {
 807            status.SetEntry(this[entryIndex]);
 808            status.SetOperation(TestOperation.EntryHeader);
 809            resultHandler(status, null);
 810          }
 811
 812          try {
 813            TestLocalHeader(this[entryIndex], test);
 814          } catch (ZipException ex) {
 815            status.AddError();
 816
 817            if (resultHandler != null) {
 818              resultHandler(status,
 819                string.Format("Exception during test - '{0}'", ex.Message));
 820            }
 821
 822            testing &= strategy != TestStrategy.FindFirstError;
 823          }
 824
 825          if (testing && testData && this[entryIndex].IsFile) {
 826            if (resultHandler != null) {
 827              status.SetOperation(TestOperation.EntryData);
 828              resultHandler(status, null);
 829            }
 830
 831            var crc = new Crc32();
 832
 833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {
 834
 835              byte[] buffer = new byte[4096];
 836              long totalBytes = 0;
 837              int bytesRead;
 838              while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
 839                crc.Update(buffer, 0, bytesRead);
 840
 841                if (resultHandler != null) {
 842                  totalBytes += bytesRead;
 843                  status.SetBytesTested(totalBytes);
 844                  resultHandler(status, null);
 845                }
 846              }
 847            }
 848
 849            if (this[entryIndex].Crc != crc.Value) {
 850              status.AddError();
 851
 852              if (resultHandler != null) {
 853                resultHandler(status, "CRC mismatch");
 854              }
 855
 856              testing &= strategy != TestStrategy.FindFirstError;
 857            }
 858
 859            if ((this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 860              var helper = new ZipHelperStream(baseStream_);
 861              var data = new DescriptorData();
 862              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
 863              if (this[entryIndex].Crc != data.Crc) {
 864                status.AddError();
 865              }
 866
 867              if (this[entryIndex].CompressedSize != data.CompressedSize) {
 868                status.AddError();
 869              }
 870
 871              if (this[entryIndex].Size != data.Size) {
 872                status.AddError();
 873              }
 874            }
 875          }
 876
 877          if (resultHandler != null) {
 878            status.SetOperation(TestOperation.EntryComplete);
 879            resultHandler(status, null);
 880          }
 881
 882          entryIndex += 1;
 883        }
 884
 885        if (resultHandler != null) {
 886          status.SetOperation(TestOperation.MiscellaneousTests);
 887          resultHandler(status, null);
 888        }
 889
 890        // TODO: the 'Corrina Johns' test where local headers are missing from
 891        // the central directory.  They are therefore invisible to many archivers.
 892      } catch (Exception ex) {
 893        status.AddError();
 894
 895        if (resultHandler != null) {
 896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
 897        }
 898      }
 899
 900      if (resultHandler != null) {
 901        status.SetOperation(TestOperation.Complete);
 902        status.SetEntry(null);
 903        resultHandler(status, null);
 904      }
 905
 906      return (status.ErrorCount == 0);
 907    }
 908
 909    [Flags]
 910    enum HeaderTest
 911    {
 912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted
 913      Header = 0x02,     // Check that this header contents are valid
 914    }
 915
 916    /// <summary>
 917    /// Test a local header against that provided from the central directory
 918    /// </summary>
 919    /// <param name="entry">
 920    /// The entry to test against
 921    /// </param>
 922    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
 923    /// <returns>The offset of the entries data in the file</returns>
 924    long TestLocalHeader(ZipEntry entry, HeaderTest tests)
 925    {
 926      lock (baseStream_) {
 927        bool testHeader = (tests & HeaderTest.Header) != 0;
 928        bool testData = (tests & HeaderTest.Extract) != 0;
 929
 930        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
 931        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
 932          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)
 933        }
 934
 935        var extractVersion = (short)(ReadLEUshort() & 0x00ff);
 936        var localFlags = (short)ReadLEUshort();
 937        var compressionMethod = (short)ReadLEUshort();
 938        var fileTime = (short)ReadLEUshort();
 939        var fileDate = (short)ReadLEUshort();
 940        uint crcValue = ReadLEUint();
 941        long compressedSize = ReadLEUint();
 942        long size = ReadLEUint();
 943        int storedNameLength = ReadLEUshort();
 944        int extraDataLength = ReadLEUshort();
 945
 946        byte[] nameData = new byte[storedNameLength];
 947        StreamUtils.ReadFully(baseStream_, nameData);
 948
 949        byte[] extraData = new byte[extraDataLength];
 950        StreamUtils.ReadFully(baseStream_, extraData);
 951
 952        var localExtraData = new ZipExtraData(extraData);
 953
 954        // Extra data / zip64 checks
 955        if (localExtraData.Find(1)) {
 956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
 957          // and size or compressedSize = MaxValue, due to rogue creators.
 958
 959          size = localExtraData.ReadLong();
 960          compressedSize = localExtraData.ReadLong();
 961
 962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {
 963            // These may be valid if patched later
 964            if ((size != -1) && (size != entry.Size)) {
 965              throw new ZipException("Size invalid for descriptor");
 966            }
 967
 968            if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {
 969              throw new ZipException("Compressed size invalid for descriptor");
 970            }
 971          }
 972        } else {
 973          // No zip64 extra data but entry requires it.
 974          if ((extractVersion >= ZipConstants.VersionZip64) &&
 975            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) {
 976            throw new ZipException("Required Zip64 extended information missing");
 977          }
 978        }
 979
 980        if (testData) {
 981          if (entry.IsFile) {
 982            if (!entry.IsCompressionMethodSupported()) {
 983              throw new ZipException("Compression method not supported");
 984            }
 985
 986            if ((extractVersion > ZipConstants.VersionMadeBy)
 987              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64))) {
 988              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract
 989            }
 990
 991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance
 992              throw new ZipException("The library does not support the zip version required to extract this entry");
 993            }
 994          }
 995        }
 996
 997        if (testHeader) {
 998          if ((extractVersion <= 63) &&   // Ignore later versions as we dont know about them..
 999            (extractVersion != 10) &&
 1000            (extractVersion != 11) &&
 1001            (extractVersion != 20) &&
 1002            (extractVersion != 21) &&
 1003            (extractVersion != 25) &&
 1004            (extractVersion != 27) &&
 1005            (extractVersion != 45) &&
 1006            (extractVersion != 46) &&
 1007            (extractVersion != 50) &&
 1008            (extractVersion != 51) &&
 1009            (extractVersion != 52) &&
 1010            (extractVersion != 61) &&
 1011            (extractVersion != 62) &&
 1012            (extractVersion != 63)
 1013            ) {
 1014            throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersi
 1015          }
 1016
 1017          // Local entry flags dont have reserved bit set on.
 1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R
 1019            throw new ZipException("Reserved bit flags cannot be set.");
 1020          }
 1021
 1022          // Encryption requires extract version >= 20
 1023          if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) {
 1024            throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})
 1025          }
 1026
 1027          // Strong encryption requires encryption flag to be set and extract version >= 50.
 1028          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1029            if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) {
 1030              throw new ZipException("Strong encryption flag set but encryption flag is not set");
 1031            }
 1032
 1033            if (extractVersion < 50) {
 1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0
 1035            }
 1036          }
 1037
 1038          // Patched entries require extract version >= 27
 1039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {
 1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
 1041          }
 1042
 1043          // Central header flags match local entry flags.
 1044          if (localFlags != entry.Flags) {
 1045            throw new ZipException("Central header/local header flags mismatch");
 1046          }
 1047
 1048          // Central header compression method matches local entry
 1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {
 1050            throw new ZipException("Central header/local header compression method mismatch");
 1051          }
 1052
 1053          if (entry.Version != extractVersion) {
 1054            throw new ZipException("Extract version mismatch");
 1055          }
 1056
 1057          // Strong encryption and extract version match
 1058          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1059            if (extractVersion < 62) {
 1060              throw new ZipException("Strong encryption flag set but version not high enough");
 1061            }
 1062          }
 1063
 1064          if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) {
 1065            if ((fileTime != 0) || (fileDate != 0)) {
 1066              throw new ZipException("Header masked set but date/time values non-zero");
 1067            }
 1068          }
 1069
 1070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
 1071            if (crcValue != (uint)entry.Crc) {
 1072              throw new ZipException("Central header/local header crc mismatch");
 1073            }
 1074          }
 1075
 1076          // Crc valid for empty entry.
 1077          // This will also apply to streamed entries where size isnt known and the header cant be patched
 1078          if ((size == 0) && (compressedSize == 0)) {
 1079            if (crcValue != 0) {
 1080              throw new ZipException("Invalid CRC for empty entry");
 1081            }
 1082          }
 1083
 1084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str
 1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
 1086          if (entry.Name.Length > storedNameLength) {
 1087            throw new ZipException("File name length mismatch");
 1088          }
 1089
 1090          // Name data has already been read convert it and compare.
 1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);
 1092
 1093          // Central directory and local entry name match
 1094          if (localName != entry.Name) {
 1095            throw new ZipException("Central header and local header file name mismatch");
 1096          }
 1097
 1098          // Directories have zero actual size but can have compressed size
 1099          if (entry.IsDirectory) {
 1100            if (size > 0) {
 1101              throw new ZipException("Directory cannot have size");
 1102            }
 1103
 1104            // There may be other cases where the compressed size can be greater than this?
 1105            // If so until details are known we will be strict.
 1106            if (entry.IsCrypted) {
 1107              if (compressedSize > ZipConstants.CryptoHeaderSize + 2) {
 1108                throw new ZipException("Directory compressed size invalid");
 1109              }
 1110            } else if (compressedSize > 2) {
 1111              // When not compressed the directory size can validly be 2 bytes
 1112              // if the true size wasnt known when data was originally being written.
 1113              // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
 1114              throw new ZipException("Directory compressed size invalid");
 1115            }
 1116          }
 1117
 1118          if (!ZipNameTransform.IsValidName(localName, true)) {
 1119            throw new ZipException("Name is invalid");
 1120          }
 1121        }
 1122
 1123        // Tests that apply to both data and header.
 1124
 1125        // Size can be verified only if it is known in the local header.
 1126        // it will always be known in the central header.
 1127        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
 1128          ((size > 0 || compressedSize > 0) && entry.Size > 0)) {
 1129
 1130          if ((size != 0)
 1131            && (size != entry.Size)) {
 1132            throw new ZipException(
 1133              string.Format("Size mismatch between central header({0}) and local header({1})",
 1134                entry.Size, size));
 1135          }
 1136
 1137          if ((compressedSize != 0)
 1138            && (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) {
 1139            throw new ZipException(
 1140              string.Format("Compressed size mismatch between central header({0}) and local header({1})",
 1141              entry.CompressedSize, compressedSize));
 1142          }
 1143        }
 1144
 1145        int extraLength = storedNameLength + extraDataLength;
 1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
 1147      }
 1148    }
 1149
 1150    #endregion
 1151
 1152    #region Updating
 1153
 1154    const int DefaultBufferSize = 4096;
 1155
 1156    /// <summary>
 1157    /// The kind of update to apply.
 1158    /// </summary>
 1159    enum UpdateCommand
 1160    {
 1161      Copy,       // Copy original file contents.
 1162      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.
 1163      Add,        // Add a new file to the archive.
 1164    }
 1165
 1166    #region Properties
 1167    /// <summary>
 1168    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.
 1169    /// </summary>
 1170    public INameTransform NameTransform {
 1171      get {
 1172        return updateEntryFactory_.NameTransform;
 1173      }
 1174
 1175      set {
 1176        updateEntryFactory_.NameTransform = value;
 1177      }
 1178    }
 1179
 1180    /// <summary>
 1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values
 1182    /// during updates.
 1183    /// </summary>
 1184    public IEntryFactory EntryFactory {
 1185      get {
 1186        return updateEntryFactory_;
 1187      }
 1188
 1189      set {
 1190        if (value == null) {
 1191          updateEntryFactory_ = new ZipEntryFactory();
 1192        } else {
 1193          updateEntryFactory_ = value;
 1194        }
 1195      }
 1196    }
 1197
 1198    /// <summary>
 1199    /// Get /set the buffer size to be used when updating this zip file.
 1200    /// </summary>
 1201    public int BufferSize {
 1202      get { return bufferSize_; }
 1203      set {
 1204        if (value < 1024) {
 1205          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");
 1206        }
 1207
 1208        if (bufferSize_ != value) {
 1209          bufferSize_ = value;
 1210          copyBuffer_ = null;
 1211        }
 1212      }
 1213    }
 1214
 1215    /// <summary>
 1216    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.
 1217    /// </summary>
 1218    public bool IsUpdating {
 1219      get { return updates_ != null; }
 1220    }
 1221
 1222    /// <summary>
 1223    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
 1224    /// </summary>
 1225    public UseZip64 UseZip64 {
 1226      get { return useZip64_; }
 1227      set { useZip64_ = value; }
 1228    }
 1229
 1230    #endregion
 1231
 1232    #region Immediate updating
 1233    //    TBD: Direct form of updating
 1234    //
 1235    //    public void Update(IEntryMatcher deleteMatcher)
 1236    //    {
 1237    //    }
 1238    //
 1239    //    public void Update(IScanner addScanner)
 1240    //    {
 1241    //    }
 1242    #endregion
 1243
 1244    #region Deferred Updating
 1245    /// <summary>
 1246    /// Begin updating this <see cref="ZipFile"/> archive.
 1247    /// </summary>
 1248    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p
 1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param
 1250    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1251    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>
 1252    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1253    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)
 1254    {
 1255      if (archiveStorage == null) {
 1256        throw new ArgumentNullException(nameof(archiveStorage));
 1257      }
 1258
 1259      if (dataSource == null) {
 1260        throw new ArgumentNullException(nameof(dataSource));
 1261      }
 1262
 1263      if (isDisposed_) {
 1264        throw new ObjectDisposedException("ZipFile");
 1265      }
 1266
 1267      if (IsEmbeddedArchive) {
 1268        throw new ZipException("Cannot update embedded/SFX archives");
 1269      }
 1270
 1271      archiveStorage_ = archiveStorage;
 1272      updateDataSource_ = dataSource;
 1273
 1274      // NOTE: the baseStream_ may not currently support writing or seeking.
 1275
 1276      updateIndex_ = new Hashtable();
 1277
 1278      updates_ = new ArrayList(entries_.Length);
 1279      foreach (ZipEntry entry in entries_) {
 1280        int index = updates_.Add(new ZipUpdate(entry));
 1281        updateIndex_.Add(entry.Name, index);
 1282      }
 1283
 1284      // We must sort by offset before using offset's calculated sizes
 1285      updates_.Sort(new UpdateComparer());
 1286
 1287      int idx = 0;
 1288      foreach (ZipUpdate update in updates_) {
 1289        //If last entry, there is no next entry offset to use
 1290        if (idx == updates_.Count - 1)
 1291          break;
 1292
 1293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;
 1294        idx++;
 1295      }
 1296      updateCount_ = updates_.Count;
 1297
 1298      contentsEdited_ = false;
 1299      commentEdited_ = false;
 1300      newComment_ = null;
 1301    }
 1302
 1303    /// <summary>
 1304    /// Begin updating to this <see cref="ZipFile"/> archive.
 1305    /// </summary>
 1306    /// <param name="archiveStorage">The storage to use during the update.</param>
 1307    public void BeginUpdate(IArchiveStorage archiveStorage)
 1308    {
 1309      BeginUpdate(archiveStorage, new DynamicDiskDataSource());
 1310    }
 1311
 1312    /// <summary>
 1313    /// Begin updating this <see cref="ZipFile"/> archive.
 1314    /// </summary>
 1315    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>
 1316    /// <seealso cref="CommitUpdate"></seealso>
 1317    /// <seealso cref="AbortUpdate"></seealso>
 1318    public void BeginUpdate()
 1319    {
 1320      if (Name == null) {
 1321        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());
 1322      } else {
 1323        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());
 1324      }
 1325    }
 1326
 1327    /// <summary>
 1328    /// Commit current updates, updating this archive.
 1329    /// </summary>
 1330    /// <seealso cref="BeginUpdate()"></seealso>
 1331    /// <seealso cref="AbortUpdate"></seealso>
 1332    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1333    public void CommitUpdate()
 1334    {
 1335      if (isDisposed_) {
 1336        throw new ObjectDisposedException("ZipFile");
 1337      }
 1338
 1339      CheckUpdating();
 1340
 1341      try {
 1342        updateIndex_.Clear();
 1343        updateIndex_ = null;
 1344
 1345        if (contentsEdited_) {
 1346          RunUpdates();
 1347        } else if (commentEdited_) {
 1348          UpdateCommentOnly();
 1349        } else {
 1350          // Create an empty archive if none existed originally.
 1351          if (entries_.Length == 0) {
 1352            byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 1353            using (ZipHelperStream zhs = new ZipHelperStream(baseStream_)) {
 1354              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
 1355            }
 1356          }
 1357        }
 1358
 1359      } finally {
 1360        PostUpdateCleanup();
 1361      }
 1362    }
 1363
 1364    /// <summary>
 1365    /// Abort updating leaving the archive unchanged.
 1366    /// </summary>
 1367    /// <seealso cref="BeginUpdate()"></seealso>
 1368    /// <seealso cref="CommitUpdate"></seealso>
 1369    public void AbortUpdate()
 1370    {
 1371      PostUpdateCleanup();
 1372    }
 1373
 1374    /// <summary>
 1375    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.
 1376    /// </summary>
 1377    /// <param name="comment">The comment to record.</param>
 1378    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1379    public void SetComment(string comment)
 1380    {
 1381      if (isDisposed_) {
 1382        throw new ObjectDisposedException("ZipFile");
 1383      }
 1384
 1385      CheckUpdating();
 1386
 1387      newComment_ = new ZipString(comment);
 1388
 1389      if (newComment_.RawLength > 0xffff) {
 1390        newComment_ = null;
 1391        throw new ZipException("Comment length exceeds maximum - 65535");
 1392      }
 1393
 1394      // We dont take account of the original and current comment appearing to be the same
 1395      // as encoding may be different.
 1396      commentEdited_ = true;
 1397    }
 1398
 1399    #endregion
 1400
 1401    #region Adding Entries
 1402
 1403    void AddUpdate(ZipUpdate update)
 1404    {
 1405      contentsEdited_ = true;
 1406
 1407      int index = FindExistingUpdate(update.Entry.Name);
 1408
 1409      if (index >= 0) {
 1410        if (updates_[index] == null) {
 1411          updateCount_ += 1;
 1412        }
 1413
 1414        // Direct replacement is faster than delete and add.
 1415        updates_[index] = update;
 1416      } else {
 1417        index = updates_.Add(update);
 1418        updateCount_ += 1;
 1419        updateIndex_.Add(update.Entry.Name, index);
 1420      }
 1421    }
 1422
 1423    /// <summary>
 1424    /// Add a new entry to the archive.
 1425    /// </summary>
 1426    /// <param name="fileName">The name of the file to add.</param>
 1427    /// <param name="compressionMethod">The compression method to use.</param>
 1428    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>
 1429    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1430    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1431    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>
 1432    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText)
 1433    {
 1434      if (fileName == null) {
 1435        throw new ArgumentNullException(nameof(fileName));
 1436      }
 1437
 1438      if (isDisposed_) {
 1439        throw new ObjectDisposedException("ZipFile");
 1440      }
 1441
 1442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1444      }
 1445
 1446      CheckUpdating();
 1447      contentsEdited_ = true;
 1448
 1449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1450      entry.IsUnicodeText = useUnicodeText;
 1451      entry.CompressionMethod = compressionMethod;
 1452
 1453      AddUpdate(new ZipUpdate(fileName, entry));
 1454    }
 1455
 1456    /// <summary>
 1457    /// Add a new entry to the archive.
 1458    /// </summary>
 1459    /// <param name="fileName">The name of the file to add.</param>
 1460    /// <param name="compressionMethod">The compression method to use.</param>
 1461    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>
 1462    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>
 1463    public void Add(string fileName, CompressionMethod compressionMethod)
 1464    {
 1465      if (fileName == null) {
 1466        throw new ArgumentNullException(nameof(fileName));
 1467      }
 1468
 1469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1471      }
 1472
 1473      CheckUpdating();
 1474      contentsEdited_ = true;
 1475
 1476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1477      entry.CompressionMethod = compressionMethod;
 1478      AddUpdate(new ZipUpdate(fileName, entry));
 1479    }
 1480
 1481    /// <summary>
 1482    /// Add a file to the archive.
 1483    /// </summary>
 1484    /// <param name="fileName">The name of the file to add.</param>
 1485    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1486    public void Add(string fileName)
 1487    {
 1488      if (fileName == null) {
 1489        throw new ArgumentNullException(nameof(fileName));
 1490      }
 1491
 1492      CheckUpdating();
 1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));
 1494    }
 1495
 1496    /// <summary>
 1497    /// Add a file to the archive.
 1498    /// </summary>
 1499    /// <param name="fileName">The name of the file to add.</param>
 1500    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>
 1501    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1502    public void Add(string fileName, string entryName)
 1503    {
 1504      if (fileName == null) {
 1505        throw new ArgumentNullException(nameof(fileName));
 1506      }
 1507
 1508      if (entryName == null) {
 1509        throw new ArgumentNullException(nameof(entryName));
 1510      }
 1511
 1512      CheckUpdating();
 1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));
 1514    }
 1515
 1516
 1517    /// <summary>
 1518    /// Add a file entry with data.
 1519    /// </summary>
 1520    /// <param name="dataSource">The source of the data for this entry.</param>
 1521    /// <param name="entryName">The name to give to the entry.</param>
 1522    public void Add(IStaticDataSource dataSource, string entryName)
 1523    {
 1524      if (dataSource == null) {
 1525        throw new ArgumentNullException(nameof(dataSource));
 1526      }
 1527
 1528      if (entryName == null) {
 1529        throw new ArgumentNullException(nameof(entryName));
 1530      }
 1531
 1532      CheckUpdating();
 1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));
 1534    }
 1535
 1536    /// <summary>
 1537    /// Add a file entry with data.
 1538    /// </summary>
 1539    /// <param name="dataSource">The source of the data for this entry.</param>
 1540    /// <param name="entryName">The name to give to the entry.</param>
 1541    /// <param name="compressionMethod">The compression method to use.</param>
 1542    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 1543    {
 1544      if (dataSource == null) {
 1545        throw new ArgumentNullException(nameof(dataSource));
 1546      }
 1547
 1548      if (entryName == null) {
 1549        throw new ArgumentNullException(nameof(entryName));
 1550      }
 1551
 1552      CheckUpdating();
 1553
 1554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1555      entry.CompressionMethod = compressionMethod;
 1556
 1557      AddUpdate(new ZipUpdate(dataSource, entry));
 1558    }
 1559
 1560    /// <summary>
 1561    /// Add a file entry with data.
 1562    /// </summary>
 1563    /// <param name="dataSource">The source of the data for this entry.</param>
 1564    /// <param name="entryName">The name to give to the entry.</param>
 1565    /// <param name="compressionMethod">The compression method to use.</param>
 1566    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>
 1567    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode
 1568    {
 1569      if (dataSource == null) {
 1570        throw new ArgumentNullException(nameof(dataSource));
 1571      }
 1572
 1573      if (entryName == null) {
 1574        throw new ArgumentNullException(nameof(entryName));
 1575      }
 1576
 1577      CheckUpdating();
 1578
 1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1580      entry.IsUnicodeText = useUnicodeText;
 1581      entry.CompressionMethod = compressionMethod;
 1582
 1583      AddUpdate(new ZipUpdate(dataSource, entry));
 1584    }
 1585
 1586    /// <summary>
 1587    /// Add a <see cref="ZipEntry"/> that contains no data.
 1588    /// </summary>
 1589    /// <param name="entry">The entry to add.</param>
 1590    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
 1591    public void Add(ZipEntry entry)
 1592    {
 1593      if (entry == null) {
 1594        throw new ArgumentNullException(nameof(entry));
 1595      }
 1596
 1597      CheckUpdating();
 1598
 1599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {
 1600        throw new ZipException("Entry cannot have any data");
 1601      }
 1602
 1603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
 1604    }
 1605
 1606    /// <summary>
 1607    /// Add a directory entry to the archive.
 1608    /// </summary>
 1609    /// <param name="directoryName">The directory to add.</param>
 1610    public void AddDirectory(string directoryName)
 1611    {
 1612      if (directoryName == null) {
 1613        throw new ArgumentNullException(nameof(directoryName));
 1614      }
 1615
 1616      CheckUpdating();
 1617
 1618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);
 1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));
 1620    }
 1621
 1622    #endregion
 1623
 1624    #region Modifying Entries
 1625    /* Modify not yet ready for public consumption.
 1626       Direct modification of an entry should not overwrite original data before its read.
 1627       Safe mode is trivial in this sense.
 1628        public void Modify(ZipEntry original, ZipEntry updated)
 1629        {
 1630          if ( original == null ) {
 1631            throw new ArgumentNullException("original");
 1632          }
 1633
 1634          if ( updated == null ) {
 1635            throw new ArgumentNullException("updated");
 1636          }
 1637
 1638          CheckUpdating();
 1639          contentsEdited_ = true;
 1640          updates_.Add(new ZipUpdate(original, updated));
 1641        }
 1642    */
 1643    #endregion
 1644
 1645    #region Deleting Entries
 1646    /// <summary>
 1647    /// Delete an entry by name
 1648    /// </summary>
 1649    /// <param name="fileName">The filename to delete</param>
 1650    /// <returns>True if the entry was found and deleted; false otherwise.</returns>
 1651    public bool Delete(string fileName)
 1652    {
 1653      if (fileName == null) {
 1654        throw new ArgumentNullException(nameof(fileName));
 1655      }
 1656
 1657      CheckUpdating();
 1658
 1659      bool result = false;
 1660      int index = FindExistingUpdate(fileName);
 1661      if ((index >= 0) && (updates_[index] != null)) {
 1662        result = true;
 1663        contentsEdited_ = true;
 1664        updates_[index] = null;
 1665        updateCount_ -= 1;
 1666      } else {
 1667        throw new ZipException("Cannot find entry to delete");
 1668      }
 1669      return result;
 1670    }
 1671
 1672    /// <summary>
 1673    /// Delete a <see cref="ZipEntry"/> from the archive.
 1674    /// </summary>
 1675    /// <param name="entry">The entry to delete.</param>
 1676    public void Delete(ZipEntry entry)
 1677    {
 1678      if (entry == null) {
 1679        throw new ArgumentNullException(nameof(entry));
 1680      }
 1681
 1682      CheckUpdating();
 1683
 1684      int index = FindExistingUpdate(entry);
 1685      if (index >= 0) {
 1686        contentsEdited_ = true;
 1687        updates_[index] = null;
 1688        updateCount_ -= 1;
 1689      } else {
 1690        throw new ZipException("Cannot find entry to delete");
 1691      }
 1692    }
 1693
 1694    #endregion
 1695
 1696    #region Update Support
 1697
 1698    #region Writing Values/Headers
 1699    void WriteLEShort(int value)
 1700    {
 1701      baseStream_.WriteByte((byte)(value & 0xff));
 1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));
 1703    }
 1704
 1705    /// <summary>
 1706    /// Write an unsigned short in little endian byte order.
 1707    /// </summary>
 1708    void WriteLEUshort(ushort value)
 1709    {
 1710      baseStream_.WriteByte((byte)(value & 0xff));
 1711      baseStream_.WriteByte((byte)(value >> 8));
 1712    }
 1713
 1714    /// <summary>
 1715    /// Write an int in little endian byte order.
 1716    /// </summary>
 1717    void WriteLEInt(int value)
 1718    {
 1719      WriteLEShort(value & 0xffff);
 1720      WriteLEShort(value >> 16);
 1721    }
 1722
 1723    /// <summary>
 1724    /// Write an unsigned int in little endian byte order.
 1725    /// </summary>
 1726    void WriteLEUint(uint value)
 1727    {
 1728      WriteLEUshort((ushort)(value & 0xffff));
 1729      WriteLEUshort((ushort)(value >> 16));
 1730    }
 1731
 1732    /// <summary>
 1733    /// Write a long in little endian byte order.
 1734    /// </summary>
 1735    void WriteLeLong(long value)
 1736    {
 1737      WriteLEInt((int)(value & 0xffffffff));
 1738      WriteLEInt((int)(value >> 32));
 1739    }
 1740
 1741    void WriteLEUlong(ulong value)
 1742    {
 1743      WriteLEUint((uint)(value & 0xffffffff));
 1744      WriteLEUint((uint)(value >> 32));
 1745    }
 1746
 1747    void WriteLocalEntryHeader(ZipUpdate update)
 1748    {
 1749      ZipEntry entry = update.OutEntry;
 1750
 1751      // TODO: Local offset will require adjusting for multi-disk zip files.
 1752      entry.Offset = baseStream_.Position;
 1753
 1754      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
 1755      if (update.Command != UpdateCommand.Copy) {
 1756        if (entry.CompressionMethod == CompressionMethod.Deflated) {
 1757          if (entry.Size == 0) {
 1758            // No need to compress - no data.
 1759            entry.CompressedSize = entry.Size;
 1760            entry.Crc = 0;
 1761            entry.CompressionMethod = CompressionMethod.Stored;
 1762          }
 1763        } else if (entry.CompressionMethod == CompressionMethod.Stored) {
 1764          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
 1765        }
 1766
 1767        if (HaveKeys) {
 1768          entry.IsCrypted = true;
 1769          if (entry.Crc < 0) {
 1770            entry.Flags |= (int)GeneralBitFlags.Descriptor;
 1771          }
 1772        } else {
 1773          entry.IsCrypted = false;
 1774        }
 1775
 1776        switch (useZip64_) {
 1777          case UseZip64.Dynamic:
 1778            if (entry.Size < 0) {
 1779              entry.ForceZip64();
 1780            }
 1781            break;
 1782
 1783          case UseZip64.On:
 1784            entry.ForceZip64();
 1785            break;
 1786
 1787          case UseZip64.Off:
 1788            // Do nothing.  The entry itself may be using Zip64 independantly.
 1789            break;
 1790        }
 1791      }
 1792
 1793      // Write the local file header
 1794      WriteLEInt(ZipConstants.LocalHeaderSignature);
 1795
 1796      WriteLEShort(entry.Version);
 1797      WriteLEShort(entry.Flags);
 1798
 1799      WriteLEShort((byte)entry.CompressionMethod);
 1800      WriteLEInt((int)entry.DosTime);
 1801
 1802      if (!entry.HasCrc) {
 1803        // Note patch address for updating CRC later.
 1804        update.CrcPatchOffset = baseStream_.Position;
 1805        WriteLEInt((int)0);
 1806      } else {
 1807        WriteLEInt(unchecked((int)entry.Crc));
 1808      }
 1809
 1810      if (entry.LocalHeaderRequiresZip64) {
 1811        WriteLEInt(-1);
 1812        WriteLEInt(-1);
 1813      } else {
 1814        if ((entry.CompressedSize < 0) || (entry.Size < 0)) {
 1815          update.SizePatchOffset = baseStream_.Position;
 1816        }
 1817
 1818        WriteLEInt((int)entry.CompressedSize);
 1819        WriteLEInt((int)entry.Size);
 1820      }
 1821
 1822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1823
 1824      if (name.Length > 0xFFFF) {
 1825        throw new ZipException("Entry name too long.");
 1826      }
 1827
 1828      var ed = new ZipExtraData(entry.ExtraData);
 1829
 1830      if (entry.LocalHeaderRequiresZip64) {
 1831        ed.StartNewEntry();
 1832
 1833        // Local entry header always includes size and compressed size.
 1834        // NOTE the order of these fields is reversed when compared to the normal headers!
 1835        ed.AddLeLong(entry.Size);
 1836        ed.AddLeLong(entry.CompressedSize);
 1837        ed.AddNewEntry(1);
 1838      } else {
 1839        ed.Delete(1);
 1840      }
 1841
 1842      entry.ExtraData = ed.GetEntryData();
 1843
 1844      WriteLEShort(name.Length);
 1845      WriteLEShort(entry.ExtraData.Length);
 1846
 1847      if (name.Length > 0) {
 1848        baseStream_.Write(name, 0, name.Length);
 1849      }
 1850
 1851      if (entry.LocalHeaderRequiresZip64) {
 1852        if (!ed.Find(1)) {
 1853          throw new ZipException("Internal error cannot find extra data");
 1854        }
 1855
 1856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
 1857      }
 1858
 1859      if (entry.ExtraData.Length > 0) {
 1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
 1861      }
 1862    }
 1863
 1864    int WriteCentralDirectoryHeader(ZipEntry entry)
 1865    {
 1866      if (entry.CompressedSize < 0) {
 1867        throw new ZipException("Attempt to write central directory entry with unknown csize");
 1868      }
 1869
 1870      if (entry.Size < 0) {
 1871        throw new ZipException("Attempt to write central directory entry with unknown size");
 1872      }
 1873
 1874      if (entry.Crc < 0) {
 1875        throw new ZipException("Attempt to write central directory entry with unknown crc");
 1876      }
 1877
 1878      // Write the central file header
 1879      WriteLEInt(ZipConstants.CentralHeaderSignature);
 1880
 1881      // Version made by
 1882      WriteLEShort(ZipConstants.VersionMadeBy);
 1883
 1884      // Version required to extract
 1885      WriteLEShort(entry.Version);
 1886
 1887      WriteLEShort(entry.Flags);
 1888
 1889      unchecked {
 1890        WriteLEShort((byte)entry.CompressionMethod);
 1891        WriteLEInt((int)entry.DosTime);
 1892        WriteLEInt((int)entry.Crc);
 1893      }
 1894
 1895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {
 1896        WriteLEInt(-1);
 1897      } else {
 1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
 1899      }
 1900
 1901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {
 1902        WriteLEInt(-1);
 1903      } else {
 1904        WriteLEInt((int)entry.Size);
 1905      }
 1906
 1907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1908
 1909      if (name.Length > 0xFFFF) {
 1910        throw new ZipException("Entry name is too long.");
 1911      }
 1912
 1913      WriteLEShort(name.Length);
 1914
 1915      // Central header extra data is different to local header version so regenerate.
 1916      var ed = new ZipExtraData(entry.ExtraData);
 1917
 1918      if (entry.CentralHeaderRequiresZip64) {
 1919        ed.StartNewEntry();
 1920
 1921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1922          ed.AddLeLong(entry.Size);
 1923        }
 1924
 1925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1926          ed.AddLeLong(entry.CompressedSize);
 1927        }
 1928
 1929        if (entry.Offset >= 0xffffffff) {
 1930          ed.AddLeLong(entry.Offset);
 1931        }
 1932
 1933        // Number of disk on which this file starts isnt supported and is never written here.
 1934        ed.AddNewEntry(1);
 1935      } else {
 1936        // Should have already be done when local header was added.
 1937        ed.Delete(1);
 1938      }
 1939
 1940      byte[] centralExtraData = ed.GetEntryData();
 1941
 1942      WriteLEShort(centralExtraData.Length);
 1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);
 1944
 1945      WriteLEShort(0);    // disk number
 1946      WriteLEShort(0);    // internal file attributes
 1947
 1948      // External file attributes...
 1949      if (entry.ExternalFileAttributes != -1) {
 1950        WriteLEInt(entry.ExternalFileAttributes);
 1951      } else {
 1952        if (entry.IsDirectory) {
 1953          WriteLEUint(16);
 1954        } else {
 1955          WriteLEUint(0);
 1956        }
 1957      }
 1958
 1959      if (entry.Offset >= 0xffffffff) {
 1960        WriteLEUint(0xffffffff);
 1961      } else {
 1962        WriteLEUint((uint)(int)entry.Offset);
 1963      }
 1964
 1965      if (name.Length > 0) {
 1966        baseStream_.Write(name, 0, name.Length);
 1967      }
 1968
 1969      if (centralExtraData.Length > 0) {
 1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
 1971      }
 1972
 1973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];
 1974
 1975      if (rawComment.Length > 0) {
 1976        baseStream_.Write(rawComment, 0, rawComment.Length);
 1977      }
 1978
 1979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
 1980    }
 1981    #endregion
 1982
 1983    void PostUpdateCleanup()
 1984    {
 1985      updateDataSource_ = null;
 1986      updates_ = null;
 1987      updateIndex_ = null;
 1988
 1989      if (archiveStorage_ != null) {
 1990        archiveStorage_.Dispose();
 1991        archiveStorage_ = null;
 1992      }
 1993    }
 1994
 1995    string GetTransformedFileName(string name)
 1996    {
 1997      INameTransform transform = NameTransform;
 1998      return (transform != null) ?
 1999        transform.TransformFile(name) :
 2000        name;
 2001    }
 2002
 2003    string GetTransformedDirectoryName(string name)
 2004    {
 2005      INameTransform transform = NameTransform;
 2006      return (transform != null) ?
 2007        transform.TransformDirectory(name) :
 2008        name;
 2009    }
 2010
 2011    /// <summary>
 2012    /// Get a raw memory buffer.
 2013    /// </summary>
 2014    /// <returns>Returns a raw memory buffer.</returns>
 2015    byte[] GetBuffer()
 2016    {
 2017      if (copyBuffer_ == null) {
 2018        copyBuffer_ = new byte[bufferSize_];
 2019      }
 2020      return copyBuffer_;
 2021    }
 2022
 2023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)
 2024    {
 2025      int bytesToCopy = GetDescriptorSize(update);
 2026
 2027      if (bytesToCopy > 0) {
 2028        byte[] buffer = GetBuffer();
 2029
 2030        while (bytesToCopy > 0) {
 2031          int readSize = Math.Min(buffer.Length, bytesToCopy);
 2032
 2033          int bytesRead = source.Read(buffer, 0, readSize);
 2034          if (bytesRead > 0) {
 2035            dest.Write(buffer, 0, bytesRead);
 2036            bytesToCopy -= bytesRead;
 2037          } else {
 2038            throw new ZipException("Unxpected end of stream");
 2039          }
 2040        }
 2041      }
 2042    }
 2043
 2044    void CopyBytes(ZipUpdate update, Stream destination, Stream source,
 2045      long bytesToCopy, bool updateCrc)
 2046    {
 2047      if (destination == source) {
 2048        throw new InvalidOperationException("Destination and source are the same");
 2049      }
 2050
 2051      // NOTE: Compressed size is updated elsewhere.
 2052      var crc = new Crc32();
 2053      byte[] buffer = GetBuffer();
 2054
 2055      long targetBytes = bytesToCopy;
 2056      long totalBytesRead = 0;
 2057
 2058      int bytesRead;
 2059      do {
 2060        int readSize = buffer.Length;
 2061
 2062        if (bytesToCopy < readSize) {
 2063          readSize = (int)bytesToCopy;
 2064        }
 2065
 2066        bytesRead = source.Read(buffer, 0, readSize);
 2067        if (bytesRead > 0) {
 2068          if (updateCrc) {
 2069            crc.Update(buffer, 0, bytesRead);
 2070          }
 2071          destination.Write(buffer, 0, bytesRead);
 2072          bytesToCopy -= bytesRead;
 2073          totalBytesRead += bytesRead;
 2074        }
 2075      }
 2076      while ((bytesRead > 0) && (bytesToCopy > 0));
 2077
 2078      if (totalBytesRead != targetBytes) {
 2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2080      }
 2081
 2082      if (updateCrc) {
 2083        update.OutEntry.Crc = crc.Value;
 2084      }
 2085    }
 2086
 2087    /// <summary>
 2088    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
 2089    /// </summary>
 2090    /// <param name="update">The update to get the size for.</param>
 2091    /// <returns>The descriptor size, zero if there isnt one.</returns>
 2092    int GetDescriptorSize(ZipUpdate update)
 2093    {
 2094      int result = 0;
 2095      if ((update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 2096        result = ZipConstants.DataDescriptorSize - 4;
 2097        if (update.Entry.LocalHeaderRequiresZip64) {
 2098          result = ZipConstants.Zip64DataDescriptorSize - 4;
 2099        }
 2100      }
 2101      return result;
 2102    }
 2103
 2104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
 2105    {
 2106      int bytesToCopy = GetDescriptorSize(update);
 2107
 2108      while (bytesToCopy > 0) {
 2109        var readSize = (int)bytesToCopy;
 2110        byte[] buffer = GetBuffer();
 2111
 2112        stream.Position = sourcePosition;
 2113        int bytesRead = stream.Read(buffer, 0, readSize);
 2114        if (bytesRead > 0) {
 2115          stream.Position = destinationPosition;
 2116          stream.Write(buffer, 0, bytesRead);
 2117          bytesToCopy -= bytesRead;
 2118          destinationPosition += bytesRead;
 2119          sourcePosition += bytesRead;
 2120        } else {
 2121          throw new ZipException("Unxpected end of stream");
 2122        }
 2123      }
 2124    }
 2125
 2126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou
 2127    {
 2128      long bytesToCopy = update.Entry.CompressedSize;
 2129
 2130      // NOTE: Compressed size is updated elsewhere.
 2131      var crc = new Crc32();
 2132      byte[] buffer = GetBuffer();
 2133
 2134      long targetBytes = bytesToCopy;
 2135      long totalBytesRead = 0;
 2136
 2137      int bytesRead;
 2138      do {
 2139        int readSize = buffer.Length;
 2140
 2141        if (bytesToCopy < readSize) {
 2142          readSize = (int)bytesToCopy;
 2143        }
 2144
 2145        stream.Position = sourcePosition;
 2146        bytesRead = stream.Read(buffer, 0, readSize);
 2147        if (bytesRead > 0) {
 2148          if (updateCrc) {
 2149            crc.Update(buffer, 0, bytesRead);
 2150          }
 2151          stream.Position = destinationPosition;
 2152          stream.Write(buffer, 0, bytesRead);
 2153
 2154          destinationPosition += bytesRead;
 2155          sourcePosition += bytesRead;
 2156          bytesToCopy -= bytesRead;
 2157          totalBytesRead += bytesRead;
 2158        }
 2159      }
 2160      while ((bytesRead > 0) && (bytesToCopy > 0));
 2161
 2162      if (totalBytesRead != targetBytes) {
 2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2164      }
 2165
 2166      if (updateCrc) {
 2167        update.OutEntry.Crc = crc.Value;
 2168      }
 2169    }
 2170
 2171    int FindExistingUpdate(ZipEntry entry)
 2172    {
 2173      int result = -1;
 2174      string convertedName = GetTransformedFileName(entry.Name);
 2175
 2176      if (updateIndex_.ContainsKey(convertedName)) {
 2177        result = (int)updateIndex_[convertedName];
 2178      }
 2179      /*
 2180            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2181            // for CF?
 2182            for (int index = 0; index < updates_.Count; ++index)
 2183            {
 2184              ZipUpdate zu = ( ZipUpdate )updates_[index];
 2185              if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
 2186                (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
 2187                result = index;
 2188                break;
 2189              }
 2190            }
 2191       */
 2192      return result;
 2193    }
 2194
 2195    int FindExistingUpdate(string fileName)
 2196    {
 2197      int result = -1;
 2198
 2199      string convertedName = GetTransformedFileName(fileName);
 2200
 2201      if (updateIndex_.ContainsKey(convertedName)) {
 2202        result = (int)updateIndex_[convertedName];
 2203      }
 2204
 2205      /*
 2206            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2207            // for CF?
 2208            for ( int index = 0; index < updates_.Count; ++index ) {
 2209              if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,
 2210                true, CultureInfo.InvariantCulture) == 0 ) {
 2211                result = index;
 2212                break;
 2213              }
 2214            }
 2215       */
 2216
 2217      return result;
 2218    }
 2219
 2220    /// <summary>
 2221    /// Get an output stream for the specified <see cref="ZipEntry"/>
 2222    /// </summary>
 2223    /// <param name="entry">The entry to get an output stream for.</param>
 2224    /// <returns>The output stream obtained for the entry.</returns>
 2225    Stream GetOutputStream(ZipEntry entry)
 2226    {
 2227      Stream result = baseStream_;
 2228
 2229      if (entry.IsCrypted == true) {
 2230        result = CreateAndInitEncryptionStream(result, entry);
 2231      }
 2232
 2233      switch (entry.CompressionMethod) {
 2234        case CompressionMethod.Stored:
 2235          result = new UncompressedStream(result);
 2236          break;
 2237
 2238        case CompressionMethod.Deflated:
 2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));
 2240          dos.IsStreamOwner = false;
 2241          result = dos;
 2242          break;
 2243
 2244        default:
 2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);
 2246      }
 2247      return result;
 2248    }
 2249
 2250    void AddEntry(ZipFile workFile, ZipUpdate update)
 2251    {
 2252      Stream source = null;
 2253
 2254      if (update.Entry.IsFile) {
 2255        source = update.GetSource();
 2256
 2257        if (source == null) {
 2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);
 2259        }
 2260      }
 2261
 2262      if (source != null) {
 2263        using (source) {
 2264          long sourceStreamLength = source.Length;
 2265          if (update.OutEntry.Size < 0) {
 2266            update.OutEntry.Size = sourceStreamLength;
 2267          } else {
 2268            // Check for errant entries.
 2269            if (update.OutEntry.Size != sourceStreamLength) {
 2270              throw new ZipException("Entry size/stream size mismatch");
 2271            }
 2272          }
 2273
 2274          workFile.WriteLocalEntryHeader(update);
 2275
 2276          long dataStart = workFile.baseStream_.Position;
 2277
 2278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2279            CopyBytes(update, output, source, sourceStreamLength, true);
 2280          }
 2281
 2282          long dataEnd = workFile.baseStream_.Position;
 2283          update.OutEntry.CompressedSize = dataEnd - dataStart;
 2284
 2285          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor) {
 2286            var helper = new ZipHelperStream(workFile.baseStream_);
 2287            helper.WriteDataDescriptor(update.OutEntry);
 2288          }
 2289        }
 2290      } else {
 2291        workFile.WriteLocalEntryHeader(update);
 2292        update.OutEntry.CompressedSize = 0;
 2293      }
 2294
 2295    }
 2296
 2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)
 2298    {
 2299      workFile.WriteLocalEntryHeader(update);
 2300      long dataStart = workFile.baseStream_.Position;
 2301
 2302      // TODO: This is slow if the changes don't effect the data!!
 2303      if (update.Entry.IsFile && (update.Filename != null)) {
 2304        using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2305          using (Stream source = this.GetInputStream(update.Entry)) {
 2306            CopyBytes(update, output, source, source.Length, true);
 2307          }
 2308        }
 2309      }
 2310
 2311      long dataEnd = workFile.baseStream_.Position;
 2312      update.Entry.CompressedSize = dataEnd - dataStart;
 2313    }
 2314
 2315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)
 2316    {
 2317      bool skipOver = false || update.Entry.Offset == destinationPosition;
 2318
 2319      if (!skipOver) {
 2320        baseStream_.Position = destinationPosition;
 2321        workFile.WriteLocalEntryHeader(update);
 2322        destinationPosition = baseStream_.Position;
 2323      }
 2324
 2325      long sourcePosition = 0;
 2326
 2327      const int NameLengthOffset = 26;
 2328
 2329      // TODO: Add base for SFX friendly handling
 2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2331
 2332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2333
 2334      // Clumsy way of handling retrieving the original name and extra data length for now.
 2335      // TODO: Stop re-reading name and data length in CopyEntryDirect.
 2336      uint nameLength = ReadLEUshort();
 2337      uint extraLength = ReadLEUshort();
 2338
 2339      sourcePosition = baseStream_.Position + nameLength + extraLength;
 2340
 2341      if (skipOver) {
 2342        if (update.OffsetBasedSize != -1)
 2343          destinationPosition += update.OffsetBasedSize;
 2344        else
 2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar
 2346          // WinZip produces a warning on these entries:
 2347          // "caution: value of lrec.csize (compressed size) changed from ..."
 2348          destinationPosition +=
 2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size
 2350            update.Entry.CompressedSize + GetDescriptorSize(update);
 2351      } else {
 2352        if (update.Entry.CompressedSize > 0) {
 2353          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition);
 2354        }
 2355        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
 2356      }
 2357    }
 2358
 2359    void CopyEntry(ZipFile workFile, ZipUpdate update)
 2360    {
 2361      workFile.WriteLocalEntryHeader(update);
 2362
 2363      if (update.Entry.CompressedSize > 0) {
 2364        const int NameLengthOffset = 26;
 2365
 2366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2367
 2368        // TODO: This wont work for SFX files!
 2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2370
 2371        uint nameLength = ReadLEUshort();
 2372        uint extraLength = ReadLEUshort();
 2373
 2374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);
 2375
 2376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
 2377      }
 2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
 2379    }
 2380
 2381    void Reopen(Stream source)
 2382    {
 2383      if (source == null) {
 2384        throw new ZipException("Failed to reopen archive - no source");
 2385      }
 2386
 2387      isNewArchive_ = false;
 2388      baseStream_ = source;
 2389      ReadEntries();
 2390    }
 2391
 2392    void Reopen()
 2393    {
 2394      if (Name == null) {
 2395        throw new InvalidOperationException("Name is not known cannot Reopen");
 2396      }
 2397
 2398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));
 2399    }
 2400
 2401    void UpdateCommentOnly()
 2402    {
 2403      long baseLength = baseStream_.Length;
 2404
 2405      ZipHelperStream updateFile = null;
 2406
 2407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
 2409        updateFile = new ZipHelperStream(copyStream);
 2410        updateFile.IsStreamOwner = true;
 2411
 2412        baseStream_.Close();
 2413        baseStream_ = null;
 2414      } else {
 2415        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2416          // TODO: archiveStorage wasnt originally intended for this use.
 2417          // Need to revisit this to tidy up handling as archive storage currently doesnt
 2418          // handle the original stream well.
 2419          // The problem is when using an existing zip archive with an in memory archive storage.
 2420          // The open stream wont support writing but the memory storage should open the same file not an in memory one.
 2421
 2422          // Need to tidy up the archive storage interface and contract basically.
 2423          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);
 2424          updateFile = new ZipHelperStream(baseStream_);
 2425        } else {
 2426          baseStream_.Close();
 2427          baseStream_ = null;
 2428          updateFile = new ZipHelperStream(Name);
 2429        }
 2430      }
 2431
 2432      using (updateFile) {
 2433        long locatedCentralDirOffset =
 2434          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2435                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2436        if (locatedCentralDirOffset < 0) {
 2437          throw new ZipException("Cannot find central directory");
 2438        }
 2439
 2440        const int CentralHeaderCommentSizeOffset = 16;
 2441        updateFile.Position += CentralHeaderCommentSizeOffset;
 2442
 2443        byte[] rawComment = newComment_.RawComment;
 2444
 2445        updateFile.WriteLEShort(rawComment.Length);
 2446        updateFile.Write(rawComment, 0, rawComment.Length);
 2447        updateFile.SetLength(updateFile.Position);
 2448      }
 2449
 2450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2452      } else {
 2453        ReadEntries();
 2454      }
 2455    }
 2456
 2457    /// <summary>
 2458    /// Class used to sort updates.
 2459    /// </summary>
 2460    class UpdateComparer : IComparer
 2461    {
 2462      /// <summary>
 2463      /// Compares two objects and returns a value indicating whether one is
 2464      /// less than, equal to or greater than the other.
 2465      /// </summary>
 2466      /// <param name="x">First object to compare</param>
 2467      /// <param name="y">Second object to compare.</param>
 2468      /// <returns>Compare result.</returns>
 2469      public int Compare(
 2470        object x,
 2471        object y)
 2472      {
 2473        var zx = x as ZipUpdate;
 2474        var zy = y as ZipUpdate;
 2475
 2476        int result;
 2477
 2478        if (zx == null) {
 2479          if (zy == null) {
 2480            result = 0;
 2481          } else {
 2482            result = -1;
 2483          }
 2484        } else if (zy == null) {
 2485          result = 1;
 2486        } else {
 2487          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;
 2488          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;
 2489
 2490          result = xCmdValue - yCmdValue;
 2491          if (result == 0) {
 2492            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;
 2493            if (offsetDiff < 0) {
 2494              result = -1;
 2495            } else if (offsetDiff == 0) {
 2496              result = 0;
 2497            } else {
 2498              result = 1;
 2499            }
 2500          }
 2501        }
 2502        return result;
 2503      }
 2504    }
 2505
 2506    void RunUpdates()
 2507    {
 2508      long sizeEntries = 0;
 2509      long endOfStream = 0;
 2510      bool directUpdate = false;
 2511      long destinationPosition = 0; // NOT SFX friendly
 2512
 2513      ZipFile workFile;
 2514
 2515      if (IsNewArchive) {
 2516        workFile = this;
 2517        workFile.baseStream_.Position = 0;
 2518        directUpdate = true;
 2519      } else if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2520        workFile = this;
 2521        workFile.baseStream_.Position = 0;
 2522        directUpdate = true;
 2523
 2524        // Sort the updates by offset within copies/modifies, then adds.
 2525        // This ensures that data required by copies will not be overwritten.
 2526        updates_.Sort(new UpdateComparer());
 2527      } else {
 2528        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
 2529        workFile.UseZip64 = UseZip64;
 2530
 2531        if (key != null) {
 2532          workFile.key = (byte[])key.Clone();
 2533        }
 2534      }
 2535
 2536      try {
 2537        foreach (ZipUpdate update in updates_) {
 2538          if (update != null) {
 2539            switch (update.Command) {
 2540              case UpdateCommand.Copy:
 2541                if (directUpdate) {
 2542                  CopyEntryDirect(workFile, update, ref destinationPosition);
 2543                } else {
 2544                  CopyEntry(workFile, update);
 2545                }
 2546                break;
 2547
 2548              case UpdateCommand.Modify:
 2549                // TODO: Direct modifying of an entry will take some legwork.
 2550                ModifyEntry(workFile, update);
 2551                break;
 2552
 2553              case UpdateCommand.Add:
 2554                if (!IsNewArchive && directUpdate) {
 2555                  workFile.baseStream_.Position = destinationPosition;
 2556                }
 2557
 2558                AddEntry(workFile, update);
 2559
 2560                if (directUpdate) {
 2561                  destinationPosition = workFile.baseStream_.Position;
 2562                }
 2563                break;
 2564            }
 2565          }
 2566        }
 2567
 2568        if (!IsNewArchive && directUpdate) {
 2569          workFile.baseStream_.Position = destinationPosition;
 2570        }
 2571
 2572        long centralDirOffset = workFile.baseStream_.Position;
 2573
 2574        foreach (ZipUpdate update in updates_) {
 2575          if (update != null) {
 2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
 2577          }
 2578        }
 2579
 2580        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 2581        using (ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_)) {
 2582          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);
 2583        }
 2584
 2585        endOfStream = workFile.baseStream_.Position;
 2586
 2587        // And now patch entries...
 2588        foreach (ZipUpdate update in updates_) {
 2589          if (update != null) {
 2590            // If the size of the entry is zero leave the crc as 0 as well.
 2591            // The calculated crc will be all bits on...
 2592            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {
 2593              workFile.baseStream_.Position = update.CrcPatchOffset;
 2594              workFile.WriteLEInt((int)update.OutEntry.Crc);
 2595            }
 2596
 2597            if (update.SizePatchOffset > 0) {
 2598              workFile.baseStream_.Position = update.SizePatchOffset;
 2599              if (update.OutEntry.LocalHeaderRequiresZip64) {
 2600                workFile.WriteLeLong(update.OutEntry.Size);
 2601                workFile.WriteLeLong(update.OutEntry.CompressedSize);
 2602              } else {
 2603                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);
 2604                workFile.WriteLEInt((int)update.OutEntry.Size);
 2605              }
 2606            }
 2607          }
 2608        }
 2609      } catch {
 2610        workFile.Close();
 2611        if (!directUpdate && (workFile.Name != null)) {
 2612          File.Delete(workFile.Name);
 2613        }
 2614        throw;
 2615      }
 2616
 2617      if (directUpdate) {
 2618        workFile.baseStream_.SetLength(endOfStream);
 2619        workFile.baseStream_.Flush();
 2620        isNewArchive_ = false;
 2621        ReadEntries();
 2622      } else {
 2623        baseStream_.Close();
 2624        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2625      }
 2626    }
 2627
 2628    void CheckUpdating()
 2629    {
 2630      if (updates_ == null) {
 2631        throw new InvalidOperationException("BeginUpdate has not been called");
 2632      }
 2633    }
 2634
 2635    #endregion
 2636
 2637    #region ZipUpdate class
 2638    /// <summary>
 2639    /// Represents a pending update to a Zip file.
 2640    /// </summary>
 2641    class ZipUpdate
 2642    {
 2643      #region Constructors
 2644      public ZipUpdate(string fileName, ZipEntry entry)
 2645      {
 2646        command_ = UpdateCommand.Add;
 2647        entry_ = entry;
 2648        filename_ = fileName;
 2649      }
 2650
 2651      [Obsolete]
 2652      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 2653      {
 2654        command_ = UpdateCommand.Add;
 2655        entry_ = new ZipEntry(entryName);
 2656        entry_.CompressionMethod = compressionMethod;
 2657        filename_ = fileName;
 2658      }
 2659
 2660      [Obsolete]
 2661      public ZipUpdate(string fileName, string entryName)
 2662        : this(fileName, entryName, CompressionMethod.Deflated)
 2663      {
 2664        // Do nothing.
 2665      }
 2666
 2667      [Obsolete]
 2668      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 2669      {
 2670        command_ = UpdateCommand.Add;
 2671        entry_ = new ZipEntry(entryName);
 2672        entry_.CompressionMethod = compressionMethod;
 2673        dataSource_ = dataSource;
 2674      }
 2675
 2676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 2677      {
 2678        command_ = UpdateCommand.Add;
 2679        entry_ = entry;
 2680        dataSource_ = dataSource;
 2681      }
 2682
 2683      public ZipUpdate(ZipEntry original, ZipEntry updated)
 2684      {
 2685        throw new ZipException("Modify not currently supported");
 2686        /*
 2687          command_ = UpdateCommand.Modify;
 2688          entry_ = ( ZipEntry )original.Clone();
 2689          outEntry_ = ( ZipEntry )updated.Clone();
 2690        */
 2691      }
 2692
 2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)
 2694      {
 2695        command_ = command;
 2696        entry_ = (ZipEntry)entry.Clone();
 2697      }
 2698
 2699
 2700      /// <summary>
 2701      /// Copy an existing entry.
 2702      /// </summary>
 2703      /// <param name="entry">The existing entry to copy.</param>
 2704      public ZipUpdate(ZipEntry entry)
 2705        : this(UpdateCommand.Copy, entry)
 2706      {
 2707        // Do nothing.
 2708      }
 2709      #endregion
 2710
 2711      /// <summary>
 2712      /// Get the <see cref="ZipEntry"/> for this update.
 2713      /// </summary>
 2714      /// <remarks>This is the source or original entry.</remarks>
 2715      public ZipEntry Entry {
 2716        get { return entry_; }
 2717      }
 2718
 2719      /// <summary>
 2720      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.
 2721      /// </summary>
 2722      public ZipEntry OutEntry {
 2723        get {
 2724          if (outEntry_ == null) {
 2725            outEntry_ = (ZipEntry)entry_.Clone();
 2726          }
 2727
 2728          return outEntry_;
 2729        }
 2730      }
 2731
 2732      /// <summary>
 2733      /// Get the command for this update.
 2734      /// </summary>
 2735      public UpdateCommand Command {
 2736        get { return command_; }
 2737      }
 2738
 2739      /// <summary>
 2740      /// Get the filename if any for this update.  Null if none exists.
 2741      /// </summary>
 2742      public string Filename {
 2743        get { return filename_; }
 2744      }
 2745
 2746      /// <summary>
 2747      /// Get/set the location of the size patch for this update.
 2748      /// </summary>
 2749      public long SizePatchOffset {
 2750        get { return sizePatchOffset_; }
 2751        set { sizePatchOffset_ = value; }
 2752      }
 2753
 2754      /// <summary>
 2755      /// Get /set the location of the crc patch for this update.
 2756      /// </summary>
 2757      public long CrcPatchOffset {
 2758        get { return crcPatchOffset_; }
 2759        set { crcPatchOffset_ = value; }
 2760      }
 2761
 2762      /// <summary>
 2763      /// Get/set the size calculated by offset.
 2764      /// Specifically, the difference between this and next entry's starting offset.
 2765      /// </summary>
 2766      public long OffsetBasedSize {
 2767        get { return _offsetBasedSize; }
 2768        set { _offsetBasedSize = value; }
 2769      }
 2770
 2771      public Stream GetSource()
 2772      {
 2773        Stream result = null;
 2774        if (dataSource_ != null) {
 2775          result = dataSource_.GetSource();
 2776        }
 2777
 2778        return result;
 2779      }
 2780
 2781      #region Instance Fields
 2782      ZipEntry entry_;
 2783      ZipEntry outEntry_;
 2784      UpdateCommand command_;
 2785      IStaticDataSource dataSource_;
 2786      string filename_;
 2787      long sizePatchOffset_ = -1;
 2788      long crcPatchOffset_ = -1;
 2789      long _offsetBasedSize = -1;
 2790      #endregion
 2791    }
 2792
 2793    #endregion
 2794    #endregion
 2795
 2796    #region Disposing
 2797
 2798    #region IDisposable Members
 2799    void IDisposable.Dispose()
 2800    {
 2801      Close();
 2802    }
 2803    #endregion
 2804
 2805    void DisposeInternal(bool disposing)
 2806    {
 2807      if (!isDisposed_) {
 2808        isDisposed_ = true;
 2809        entries_ = new ZipEntry[0];
 2810
 2811        if (IsStreamOwner && (baseStream_ != null)) {
 2812          lock (baseStream_) {
 2813            baseStream_.Close();
 2814          }
 2815        }
 2816
 2817        PostUpdateCleanup();
 2818      }
 2819    }
 2820
 2821    /// <summary>
 2822    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.
 2823    /// </summary>
 2824    /// <param name="disposing">true to release both managed and unmanaged resources;
 2825    /// false to release only unmanaged resources.</param>
 2826    protected virtual void Dispose(bool disposing)
 2827    {
 2828      DisposeInternal(disposing);
 2829    }
 2830
 2831    #endregion
 2832
 2833    #region Internal routines
 2834    #region Reading
 2835    /// <summary>
 2836    /// Read an unsigned short in little endian byte order.
 2837    /// </summary>
 2838    /// <returns>Returns the value read.</returns>
 2839    /// <exception cref="EndOfStreamException">
 2840    /// The stream ends prematurely
 2841    /// </exception>
 2842    ushort ReadLEUshort()
 2843    {
 2844      int data1 = baseStream_.ReadByte();
 2845
 2846      if (data1 < 0) {
 2847        throw new EndOfStreamException("End of stream");
 2848      }
 2849
 2850      int data2 = baseStream_.ReadByte();
 2851
 2852      if (data2 < 0) {
 2853        throw new EndOfStreamException("End of stream");
 2854      }
 2855
 2856
 2857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));
 2858    }
 2859
 2860    /// <summary>
 2861    /// Read a uint in little endian byte order.
 2862    /// </summary>
 2863    /// <returns>Returns the value read.</returns>
 2864    /// <exception cref="IOException">
 2865    /// An i/o error occurs.
 2866    /// </exception>
 2867    /// <exception cref="System.IO.EndOfStreamException">
 2868    /// The file ends prematurely
 2869    /// </exception>
 2870    uint ReadLEUint()
 2871    {
 2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));
 2873    }
 2874
 2875    ulong ReadLEUlong()
 2876    {
 2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);
 2878    }
 2879
 2880    #endregion
 2881    // NOTE this returns the offset of the first byte after the signature.
 2882    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 2883    {
 2884      using (ZipHelperStream les = new ZipHelperStream(baseStream_)) {
 2885        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
 2886      }
 2887    }
 2888
 2889    /// <summary>
 2890    /// Search for and read the central directory of a zip file filling the entries array.
 2891    /// </summary>
 2892    /// <exception cref="System.IO.IOException">
 2893    /// An i/o error occurs.
 2894    /// </exception>
 2895    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 2896    /// The central directory is malformed or cannot be found
 2897    /// </exception>
 2898    void ReadEntries()
 2899    {
 2900      // Search for the End Of Central Directory.  When a zip comment is
 2901      // present the directory will start earlier
 2902      //
 2903      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
 2904      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
 2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
 2906      // this could be invalid.
 2907      // Could also speed this up by reading memory in larger blocks.
 2908
 2909      if (baseStream_.CanSeek == false) {
 2910        throw new ZipException("ZipFile stream must be seekable");
 2911      }
 2912
 2913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2915
 2916      if (locatedEndOfCentralDir < 0) {
 2917        throw new ZipException("Cannot find central directory");
 2918      }
 2919
 2920      // Read end of central directory record
 2921      ushort thisDiskNumber = ReadLEUshort();
 2922      ushort startCentralDirDisk = ReadLEUshort();
 2923      ulong entriesForThisDisk = ReadLEUshort();
 2924      ulong entriesForWholeCentralDir = ReadLEUshort();
 2925      ulong centralDirSize = ReadLEUint();
 2926      long offsetOfCentralDir = ReadLEUint();
 2927      uint commentSize = ReadLEUshort();
 2928
 2929      if (commentSize > 0) {
 2930        byte[] comment = new byte[commentSize];
 2931
 2932        StreamUtils.ReadFully(baseStream_, comment);
 2933        comment_ = ZipConstants.ConvertToString(comment);
 2934      } else {
 2935        comment_ = string.Empty;
 2936      }
 2937
 2938      bool isZip64 = false;
 2939
 2940      // Check if zip64 header information is required.
 2941      if ((thisDiskNumber == 0xffff) ||
 2942        (startCentralDirDisk == 0xffff) ||
 2943        (entriesForThisDisk == 0xffff) ||
 2944        (entriesForWholeCentralDir == 0xffff) ||
 2945        (centralDirSize == 0xffffffff) ||
 2946        (offsetOfCentralDir == 0xffffffff)) {
 2947        isZip64 = true;
 2948
 2949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 
 2950        if (offset < 0) {
 2951          throw new ZipException("Cannot find Zip64 locator");
 2952        }
 2953
 2954        // number of the disk with the start of the zip64 end of central directory 4 bytes
 2955        // relative offset of the zip64 end of central directory record 8 bytes
 2956        // total number of disks 4 bytes
 2957        ReadLEUint(); // startDisk64 is not currently used
 2958        ulong offset64 = ReadLEUlong();
 2959        uint totalDisks = ReadLEUint();
 2960
 2961        baseStream_.Position = (long)offset64;
 2962        long sig64 = ReadLEUint();
 2963
 2964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {
 2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
 2966        }
 2967
 2968        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
 2969        ulong recordSize = ReadLEUlong();
 2970        int versionMadeBy = ReadLEUshort();
 2971        int versionToExtract = ReadLEUshort();
 2972        uint thisDisk = ReadLEUint();
 2973        uint centralDirDisk = ReadLEUint();
 2974        entriesForThisDisk = ReadLEUlong();
 2975        entriesForWholeCentralDir = ReadLEUlong();
 2976        centralDirSize = ReadLEUlong();
 2977        offsetOfCentralDir = (long)ReadLEUlong();
 2978
 2979        // NOTE: zip64 extensible data sector (variable size) is ignored.
 2980      }
 2981
 2982      entries_ = new ZipEntry[entriesForThisDisk];
 2983
 2984      // SFX/embedded support, find the offset of the first entry vis the start of the stream
 2985      // This applies to Zip files that are appended to the end of an SFX stub.
 2986      // Or are appended as a resource to an executable.
 2987      // Zip files created by some archivers have the offsets altered to reflect the true offsets
 2988      // and so dont require any adjustment here...
 2989      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
 2990      if (!isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize))) {
 2991        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
 2992        if (offsetOfFirstEntry <= 0) {
 2993          throw new ZipException("Invalid embedded zip archive");
 2994        }
 2995      }
 2996
 2997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
 2998
 2999      for (ulong i = 0; i < entriesForThisDisk; i++) {
 3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
 3001          throw new ZipException("Wrong Central Directory signature");
 3002        }
 3003
 3004        int versionMadeBy = ReadLEUshort();
 3005        int versionToExtract = ReadLEUshort();
 3006        int bitFlags = ReadLEUshort();
 3007        int method = ReadLEUshort();
 3008        uint dostime = ReadLEUint();
 3009        uint crc = ReadLEUint();
 3010        var csize = (long)ReadLEUint();
 3011        var size = (long)ReadLEUint();
 3012        int nameLen = ReadLEUshort();
 3013        int extraLen = ReadLEUshort();
 3014        int commentLen = ReadLEUshort();
 3015
 3016        int diskStartNo = ReadLEUshort();  // Not currently used
 3017        int internalAttributes = ReadLEUshort();  // Not currently used
 3018
 3019        uint externalAttributes = ReadLEUint();
 3020        long offset = ReadLEUint();
 3021
 3022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
 3023
 3024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
 3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);
 3026
 3027        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
 3028        entry.Crc = crc & 0xffffffffL;
 3029        entry.Size = size & 0xffffffffL;
 3030        entry.CompressedSize = csize & 0xffffffffL;
 3031        entry.Flags = bitFlags;
 3032        entry.DosTime = (uint)dostime;
 3033        entry.ZipFileIndex = (long)i;
 3034        entry.Offset = offset;
 3035        entry.ExternalFileAttributes = (int)externalAttributes;
 3036
 3037        if ((bitFlags & 8) == 0) {
 3038          entry.CryptoCheckValue = (byte)(crc >> 24);
 3039        } else {
 3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
 3041        }
 3042
 3043        if (extraLen > 0) {
 3044          byte[] extra = new byte[extraLen];
 3045          StreamUtils.ReadFully(baseStream_, extra);
 3046          entry.ExtraData = extra;
 3047        }
 3048
 3049        entry.ProcessExtraData(false);
 3050
 3051        if (commentLen > 0) {
 3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
 3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
 3054        }
 3055
 3056        entries_[i] = entry;
 3057      }
 3058    }
 3059
 3060    /// <summary>
 3061    /// Locate the data for a given entry.
 3062    /// </summary>
 3063    /// <returns>
 3064    /// The start offset of the data.
 3065    /// </returns>
 3066    /// <exception cref="System.IO.EndOfStreamException">
 3067    /// The stream ends prematurely
 3068    /// </exception>
 3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 3070    /// The local header signature is invalid, the entry and central header file name lengths are different
 3071    /// or the local and entry compression methods dont match
 3072    /// </exception>
 3073    long LocateEntry(ZipEntry entry)
 3074    {
 3075      return TestLocalHeader(entry, HeaderTest.Extract);
 3076    }
 3077
 3078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
 3079    {
 3080      CryptoStream result = null;
 3081
 3082      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3084        var classicManaged = new PkzipClassicManaged();
 3085
 3086        OnKeysRequired(entry.Name);
 3087        if (HaveKeys == false) {
 3088          throw new ZipException("No password available for encrypted stream");
 3089        }
 3090
 3091        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
 3092        CheckClassicPassword(result, entry);
 3093      } else {
 3094        if (entry.Version == ZipConstants.VERSION_AES) {
 3095          //
 3096          OnKeysRequired(entry.Name);
 3097          if (HaveKeys == false) {
 3098            throw new ZipException("No password available for AES encrypted stream");
 3099          }
 3100          int saltLen = entry.AESSaltLen;
 3101          byte[] saltBytes = new byte[saltLen];
 3102          int saltIn = baseStream.Read(saltBytes, 0, saltLen);
 3103          if (saltIn != saltLen)
 3104            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
 3105          //
 3106          byte[] pwdVerifyRead = new byte[2];
 3107          baseStream.Read(pwdVerifyRead, 0, 2);
 3108          int blockSize = entry.AESKeySize / 8;   // bits to bytes
 3109
 3110          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
 3111          byte[] pwdVerifyCalc = decryptor.PwdVerifier;
 3112          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
 3113            throw new ZipException("Invalid password for AES");
 3114          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
 3115        } else {
 3116          throw new ZipException("Decryption method not supported");
 3117        }
 3118      }
 3119
 3120      return result;
 3121    }
 3122
 3123    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
 3124    {
 3125      CryptoStream result = null;
 3126      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3127        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3128        var classicManaged = new PkzipClassicManaged();
 3129
 3130        OnKeysRequired(entry.Name);
 3131        if (HaveKeys == false) {
 3132          throw new ZipException("No password available for encrypted stream");
 3133        }
 3134
 3135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
 3136        // which doesnt do this.
 3137        result = new CryptoStream(new UncompressedStream(baseStream),
 3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
 3139
 3140        if ((entry.Crc < 0) || (entry.Flags & 8) != 0) {
 3141          WriteEncryptionHeader(result, entry.DosTime << 16);
 3142        } else {
 3143          WriteEncryptionHeader(result, entry.Crc);
 3144        }
 3145      }
 3146      return result;
 3147    }
 3148
 3149    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
 3150    {
 3151      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
 3152      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
 3153      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
 3154        throw new ZipException("Invalid password");
 3155      }
 3156    }
 3157
 3158    static void WriteEncryptionHeader(Stream stream, long crcValue)
 3159    {
 3160      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
 3161      var rnd = new Random();
 3162      rnd.NextBytes(cryptBuffer);
 3163      cryptBuffer[11] = (byte)(crcValue >> 24);
 3164      stream.Write(cryptBuffer, 0, cryptBuffer.Length);
 3165    }
 3166
 3167    #endregion
 3168
 3169    #region Instance Fields
 3170    bool isDisposed_;
 3171    string name_;
 3172    string comment_;
 3173    string rawPassword_;
 3174    Stream baseStream_;
 3175    bool isStreamOwner;
 3176    long offsetOfFirstEntry;
 3177    ZipEntry[] entries_;
 3178    byte[] key;
 3179    bool isNewArchive_;
 3180
 3181    // Default is dynamic which is not backwards compatible and can cause problems
 3182    // with XP's built in compression which cant read Zip64 archives.
 3183    // However it does avoid the situation were a large file is added and cannot be completed correctly.
 3184    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.
 3185    UseZip64 useZip64_ = UseZip64.Dynamic;
 3186
 3187    #region Zip Update Instance Fields
 3188    ArrayList updates_;
 3189    long updateCount_; // Count is managed manually as updates_ can contain nulls!
 3190    Hashtable updateIndex_;
 3191    IArchiveStorage archiveStorage_;
 3192    IDynamicDataSource updateDataSource_;
 3193    bool contentsEdited_;
 3194    int bufferSize_ = DefaultBufferSize;
 3195    byte[] copyBuffer_;
 3196    ZipString newComment_;
 3197    bool commentEdited_;
 3198    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();
 3199    #endregion
 3200    #endregion
 3201
 3202    #region Support Classes
 3203    /// <summary>
 3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.
 3205    /// </summary>
 3206    class ZipString
 3207    {
 3208      #region Constructors
 3209      /// <summary>
 3210      /// Initialise a <see cref="ZipString"/> with a string.
 3211      /// </summary>
 3212      /// <param name="comment">The textual string form.</param>
 3213      public ZipString(string comment)
 3214      {
 3215        comment_ = comment;
 3216        isSourceString_ = true;
 3217      }
 3218
 3219      /// <summary>
 3220      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.
 3221      /// </summary>
 3222      /// <param name="rawString"></param>
 3223      public ZipString(byte[] rawString)
 3224      {
 3225        rawComment_ = rawString;
 3226      }
 3227      #endregion
 3228
 3229      /// <summary>
 3230      /// Get a value indicating the original source of data for this instance.
 3231      /// True if the source was a string; false if the source was binary data.
 3232      /// </summary>
 3233      public bool IsSourceString {
 3234        get { return isSourceString_; }
 3235      }
 3236
 3237      /// <summary>
 3238      /// Get the length of the comment when represented as raw bytes.
 3239      /// </summary>
 3240      public int RawLength {
 3241        get {
 3242          MakeBytesAvailable();
 3243          return rawComment_.Length;
 3244        }
 3245      }
 3246
 3247      /// <summary>
 3248      /// Get the comment in its 'raw' form as plain bytes.
 3249      /// </summary>
 3250      public byte[] RawComment {
 3251        get {
 3252          MakeBytesAvailable();
 3253          return (byte[])rawComment_.Clone();
 3254        }
 3255      }
 3256
 3257      /// <summary>
 3258      /// Reset the comment to its initial state.
 3259      /// </summary>
 3260      public void Reset()
 3261      {
 3262        if (isSourceString_) {
 3263          rawComment_ = null;
 3264        } else {
 3265          comment_ = null;
 3266        }
 3267      }
 3268
 3269      void MakeTextAvailable()
 3270      {
 3271        if (comment_ == null) {
 3272          comment_ = ZipConstants.ConvertToString(rawComment_);
 3273        }
 3274      }
 3275
 3276      void MakeBytesAvailable()
 3277      {
 3278        if (rawComment_ == null) {
 3279          rawComment_ = ZipConstants.ConvertToArray(comment_);
 3280        }
 3281      }
 3282
 3283      /// <summary>
 3284      /// Implicit conversion of comment to a string.
 3285      /// </summary>
 3286      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>
 3287      /// <returns>The textual equivalent for the input value.</returns>
 3288      static public implicit operator string(ZipString zipString)
 3289      {
 3290        zipString.MakeTextAvailable();
 3291        return zipString.comment_;
 3292      }
 3293
 3294      #region Instance Fields
 3295      string comment_;
 3296      byte[] rawComment_;
 3297      bool isSourceString_;
 3298      #endregion
 3299    }
 3300
 3301    /// <summary>
 3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>
 3303    /// </summary>
 3304    class ZipEntryEnumerator : IEnumerator
 3305    {
 3306      #region Constructors
 3307      public ZipEntryEnumerator(ZipEntry[] entries)
 3308      {
 3309        array = entries;
 3310      }
 3311
 3312      #endregion
 3313      #region IEnumerator Members
 3314      public object Current {
 3315        get {
 3316          return array[index];
 3317        }
 3318      }
 3319
 3320      public void Reset()
 3321      {
 3322        index = -1;
 3323      }
 3324
 3325      public bool MoveNext()
 3326      {
 3327        return (++index < array.Length);
 3328      }
 3329      #endregion
 3330      #region Instance Fields
 3331      ZipEntry[] array;
 3332      int index = -1;
 3333      #endregion
 3334    }
 3335
 3336    /// <summary>
 3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data
 3338    /// to and flush, but cannot read, seek or do anything else to.
 3339    /// </summary>
 3340    class UncompressedStream : Stream
 3341    {
 3342      #region Constructors
 3343      public UncompressedStream(Stream baseStream)
 3344      {
 3345        baseStream_ = baseStream;
 3346      }
 3347
 3348      #endregion
 3349
 3350      /// <summary>
 3351      /// Close this stream instance.
 3352      /// </summary>
 3353      public override void Close()
 3354      {
 3355        // Do nothing
 3356      }
 3357
 3358      /// <summary>
 3359      /// Gets a value indicating whether the current stream supports reading.
 3360      /// </summary>
 3361      public override bool CanRead {
 3362        get {
 3363          return false;
 3364        }
 3365      }
 3366
 3367      /// <summary>
 3368      /// Write any buffered data to underlying storage.
 3369      /// </summary>
 3370      public override void Flush()
 3371      {
 3372        baseStream_.Flush();
 3373      }
 3374
 3375      /// <summary>
 3376      /// Gets a value indicating whether the current stream supports writing.
 3377      /// </summary>
 3378      public override bool CanWrite {
 3379        get {
 3380          return baseStream_.CanWrite;
 3381        }
 3382      }
 3383
 3384      /// <summary>
 3385      /// Gets a value indicating whether the current stream supports seeking.
 3386      /// </summary>
 3387      public override bool CanSeek {
 3388        get {
 3389          return false;
 3390        }
 3391      }
 3392
 3393      /// <summary>
 3394      /// Get the length in bytes of the stream.
 3395      /// </summary>
 3396      public override long Length {
 3397        get {
 3398          return 0;
 3399        }
 3400      }
 3401
 3402      /// <summary>
 3403      /// Gets or sets the position within the current stream.
 3404      /// </summary>
 3405      public override long Position {
 3406        get {
 3407          return baseStream_.Position;
 3408        }
 3409        set {
 3410          throw new NotImplementedException();
 3411        }
 3412      }
 3413
 3414      /// <summary>
 3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3416      /// </summary>
 3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3419      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3420      /// <returns>
 3421      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3422      /// </returns>
 3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3425      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3426      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3427      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3428      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3429      public override int Read(byte[] buffer, int offset, int count)
 3430      {
 3431        return 0;
 3432      }
 3433
 3434      /// <summary>
 3435      /// Sets the position within the current stream.
 3436      /// </summary>
 3437      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3438      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3439      /// <returns>
 3440      /// The new position within the current stream.
 3441      /// </returns>
 3442      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3443      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3445      public override long Seek(long offset, SeekOrigin origin)
 3446      {
 3447        return 0;
 3448      }
 3449
 3450      /// <summary>
 3451      /// Sets the length of the current stream.
 3452      /// </summary>
 3453      /// <param name="value">The desired length of the current stream in bytes.</param>
 3454      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3455      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3456      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3457      public override void SetLength(long value)
 3458      {
 3459      }
 3460
 3461      /// <summary>
 3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3463      /// </summary>
 3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3466      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3467      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3468      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3469      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3470      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3471      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3472      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3473      public override void Write(byte[] buffer, int offset, int count)
 3474      {
 3475        baseStream_.Write(buffer, offset, count);
 3476      }
 3477
 3478      readonly
 3479
 3480      #region Instance Fields
 3481      Stream baseStream_;
 3482      #endregion
 3483    }
 3484
 3485    /// <summary>
 3486    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>
 3487    /// whose data is only a part or subsection of a file.
 3488    /// </summary>
 3489    class PartialInputStream : Stream
 3490    {
 3491      #region Constructors
 3492      /// <summary>
 3493      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.
 3494      /// </summary>
 3495      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>
 3496      /// <param name="start">The start of the partial data.</param>
 3497      /// <param name="length">The length of the partial data.</param>
 3498      public PartialInputStream(ZipFile zipFile, long start, long length)
 3499      {
 3500        start_ = start;
 3501        length_ = length;
 3502
 3503        // Although this is the only time the zipfile is used
 3504        // keeping a reference here prevents premature closure of
 3505        // this zip file and thus the baseStream_.
 3506
 3507        // Code like this will cause apparently random failures depending
 3508        // on the size of the files and when garbage is collected.
 3509        //
 3510        // ZipFile z = new ZipFile (stream);
 3511        // Stream reader = z.GetInputStream(0);
 3512        // uses reader here....
 3513        zipFile_ = zipFile;
 3514        baseStream_ = zipFile_.baseStream_;
 3515        readPos_ = start;
 3516        end_ = start + length;
 3517      }
 3518      #endregion
 3519
 3520      /// <summary>
 3521      /// Read a byte from this stream.
 3522      /// </summary>
 3523      /// <returns>Returns the byte read or -1 on end of stream.</returns>
 3524      public override int ReadByte()
 3525      {
 3526        if (readPos_ >= end_) {
 3527          // -1 is the correct value at end of stream.
 3528          return -1;
 3529        }
 3530
 3531        lock (baseStream_) {
 3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);
 3533          return baseStream_.ReadByte();
 3534        }
 3535      }
 3536
 3537      /// <summary>
 3538      /// Close this <see cref="PartialInputStream">partial input stream</see>.
 3539      /// </summary>
 3540      /// <remarks>
 3541      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.
 3542      /// </remarks>
 3543      public override void Close()
 3544      {
 3545        // Do nothing at all!
 3546      }
 3547
 3548      /// <summary>
 3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3550      /// </summary>
 3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3553      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3554      /// <returns>
 3555      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3556      /// </returns>
 3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3559      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3560      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3561      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3562      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3563      public override int Read(byte[] buffer, int offset, int count)
 3564      {
 3565        lock (baseStream_) {
 3566          if (count > end_ - readPos_) {
 3567            count = (int)(end_ - readPos_);
 3568            if (count == 0) {
 3569              return 0;
 3570            }
 3571          }
 3572          // Protect against Stream implementations that throw away their buffer on every Seek
 3573          // (for example, Mono FileStream)
 3574          if (baseStream_.Position != readPos_) {
 3575            baseStream_.Seek(readPos_, SeekOrigin.Begin);
 3576          }
 3577          int readCount = baseStream_.Read(buffer, offset, count);
 3578          if (readCount > 0) {
 3579            readPos_ += readCount;
 3580          }
 3581          return readCount;
 3582        }
 3583      }
 3584
 3585      /// <summary>
 3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3587      /// </summary>
 3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3590      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3591      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3592      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3593      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3594      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3595      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3596      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3597      public override void Write(byte[] buffer, int offset, int count)
 3598      {
 3599        throw new NotSupportedException();
 3600      }
 3601
 3602      /// <summary>
 3603      /// When overridden in a derived class, sets the length of the current stream.
 3604      /// </summary>
 3605      /// <param name="value">The desired length of the current stream in bytes.</param>
 3606      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3607      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3608      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3609      public override void SetLength(long value)
 3610      {
 3611        throw new NotSupportedException();
 3612      }
 3613
 3614      /// <summary>
 3615      /// When overridden in a derived class, sets the position within the current stream.
 3616      /// </summary>
 3617      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3618      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3619      /// <returns>
 3620      /// The new position within the current stream.
 3621      /// </returns>
 3622      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3623      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3625      public override long Seek(long offset, SeekOrigin origin)
 3626      {
 3627        long newPos = readPos_;
 3628
 3629        switch (origin) {
 3630          case SeekOrigin.Begin:
 3631            newPos = start_ + offset;
 3632            break;
 3633
 3634          case SeekOrigin.Current:
 3635            newPos = readPos_ + offset;
 3636            break;
 3637
 3638          case SeekOrigin.End:
 3639            newPos = end_ + offset;
 3640            break;
 3641        }
 3642
 3643        if (newPos < start_) {
 3644          throw new ArgumentException("Negative position is invalid");
 3645        }
 3646
 3647        if (newPos >= end_) {
 3648          throw new IOException("Cannot seek past end");
 3649        }
 3650        readPos_ = newPos;
 3651        return readPos_;
 3652      }
 3653
 3654      /// <summary>
 3655      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
 3656      /// </summary>
 3657      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3658      public override void Flush()
 3659      {
 3660        // Nothing to do.
 3661      }
 3662
 3663      /// <summary>
 3664      /// Gets or sets the position within the current stream.
 3665      /// </summary>
 3666      /// <value></value>
 3667      /// <returns>The current position within the stream.</returns>
 3668      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3669      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>
 3670      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3671      public override long Position {
 3672        get { return readPos_ - start_; }
 3673        set {
 3674          long newPos = start_ + value;
 3675
 3676          if (newPos < start_) {
 3677            throw new ArgumentException("Negative position is invalid");
 3678          }
 3679
 3680          if (newPos >= end_) {
 3681            throw new InvalidOperationException("Cannot seek past end");
 3682          }
 3683          readPos_ = newPos;
 3684        }
 3685      }
 3686
 3687      /// <summary>
 3688      /// Gets the length in bytes of the stream.
 3689      /// </summary>
 3690      /// <value></value>
 3691      /// <returns>A long value representing the length of the stream in bytes.</returns>
 3692      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep
 3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3694      public override long Length {
 3695        get { return length_; }
 3696      }
 3697
 3698      /// <summary>
 3699      /// Gets a value indicating whether the current stream supports writing.
 3700      /// </summary>
 3701      /// <value>false</value>
 3702      /// <returns>true if the stream supports writing; otherwise, false.</returns>
 3703      public override bool CanWrite {
 3704        get { return false; }
 3705      }
 3706
 3707      /// <summary>
 3708      /// Gets a value indicating whether the current stream supports seeking.
 3709      /// </summary>
 3710      /// <value>true</value>
 3711      /// <returns>true if the stream supports seeking; otherwise, false.</returns>
 3712      public override bool CanSeek {
 3713        get { return true; }
 3714      }
 3715
 3716      /// <summary>
 3717      /// Gets a value indicating whether the current stream supports reading.
 3718      /// </summary>
 3719      /// <value>true.</value>
 3720      /// <returns>true if the stream supports reading; otherwise, false.</returns>
 3721      public override bool CanRead {
 3722        get { return true; }
 3723      }
 3724
 3725      /// <summary>
 3726      /// Gets a value that determines whether the current stream can time out.
 3727      /// </summary>
 3728      /// <value></value>
 3729      /// <returns>A value that determines whether the current stream can time out.</returns>
 3730      public override bool CanTimeout {
 3731        get { return baseStream_.CanTimeout; }
 3732      }
 3733      #region Instance Fields
 3734      ZipFile zipFile_;
 3735      Stream baseStream_;
 3736      long start_;
 3737      long length_;
 3738      long readPos_;
 3739      long end_;
 3740      #endregion
 3741    }
 3742    #endregion
 3743  }
 3744
 3745  #endregion
 3746
 3747  #region DataSources
 3748  /// <summary>
 3749  /// Provides a static way to obtain a source of data for an entry.
 3750  /// </summary>
 3751  public interface IStaticDataSource
 3752  {
 3753    /// <summary>
 3754    /// Get a source of data by creating a new stream.
 3755    /// </summary>
 3756    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3757    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3758    Stream GetSource();
 3759  }
 3760
 3761  /// <summary>
 3762  /// Represents a source of data that can dynamically provide
 3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.
 3764  /// </summary>
 3765  public interface IDynamicDataSource
 3766  {
 3767    /// <summary>
 3768    /// Get a data source.
 3769    /// </summary>
 3770    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>
 3771    /// <param name="name">The name for data if known.</param>
 3772    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3773    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3774    Stream GetSource(ZipEntry entry, string name);
 3775  }
 3776
 3777  /// <summary>
 3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.
 3779  /// </summary>
 3780  public class StaticDiskDataSource : IStaticDataSource
 3781  {
 3782    /// <summary>
 3783    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>
 3784    /// </summary>
 3785    /// <param name="fileName">The name of the file to obtain data from.</param>
 03786    public StaticDiskDataSource(string fileName)
 3787    {
 03788      fileName_ = fileName;
 03789    }
 3790
 3791    #region IDataSource Members
 3792
 3793    /// <summary>
 3794    /// Get a <see cref="Stream"/> providing data.
 3795    /// </summary>
 3796    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>
 3797    public Stream GetSource()
 3798    {
 03799      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 3800    }
 3801
 3802    readonly
 3803
 3804    #endregion
 3805    #region Instance Fields
 3806    string fileName_;
 3807    #endregion
 3808  }
 3809
 3810
 3811  /// <summary>
 3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.
 3813  /// </summary>
 3814  public class DynamicDiskDataSource : IDynamicDataSource
 3815  {
 3816
 3817    #region IDataSource Members
 3818    /// <summary>
 3819    /// Get a <see cref="Stream"/> providing data for an entry.
 3820    /// </summary>
 3821    /// <param name="entry">The entry to provide data for.</param>
 3822    /// <param name="name">The file name for data if known.</param>
 3823    /// <returns>Returns a stream providing data; or null if not available</returns>
 3824    public Stream GetSource(ZipEntry entry, string name)
 3825    {
 3826      Stream result = null;
 3827
 3828      if (name != null) {
 3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 3830      }
 3831
 3832      return result;
 3833    }
 3834
 3835    #endregion
 3836  }
 3837
 3838  #endregion
 3839
 3840  #region Archive Storage
 3841  /// <summary>
 3842  /// Defines facilities for data storage when updating Zip Archives.
 3843  /// </summary>
 3844  public interface IArchiveStorage
 3845  {
 3846    /// <summary>
 3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.
 3848    /// </summary>
 3849    FileUpdateMode UpdateMode { get; }
 3850
 3851    /// <summary>
 3852    /// Get an empty <see cref="Stream"/> that can be used for temporary output.
 3853    /// </summary>
 3854    /// <returns>Returns a temporary output <see cref="Stream"/></returns>
 3855    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3856    Stream GetTemporaryOutput();
 3857
 3858    /// <summary>
 3859    /// Convert a temporary output stream to a final stream.
 3860    /// </summary>
 3861    /// <returns>The resulting final <see cref="Stream"/></returns>
 3862    /// <seealso cref="GetTemporaryOutput"/>
 3863    Stream ConvertTemporaryToFinal();
 3864
 3865    /// <summary>
 3866    /// Make a temporary copy of the original stream.
 3867    /// </summary>
 3868    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 3869    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3870    Stream MakeTemporaryCopy(Stream stream);
 3871
 3872    /// <summary>
 3873    /// Return a stream suitable for performing direct updates on the original source.
 3874    /// </summary>
 3875    /// <param name="stream">The current stream.</param>
 3876    /// <returns>Returns a stream suitable for direct updating.</returns>
 3877    /// <remarks>This may be the current stream passed.</remarks>
 3878    Stream OpenForDirectUpdate(Stream stream);
 3879
 3880    /// <summary>
 3881    /// Dispose of this instance.
 3882    /// </summary>
 3883    void Dispose();
 3884  }
 3885
 3886  /// <summary>
 3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.
 3888  /// </summary>
 3889  abstract public class BaseArchiveStorage : IArchiveStorage
 3890  {
 3891    #region Constructors
 3892    /// <summary>
 3893    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.
 3894    /// </summary>
 3895    /// <param name="updateMode">The update mode.</param>
 3896    protected BaseArchiveStorage(FileUpdateMode updateMode)
 3897    {
 3898      updateMode_ = updateMode;
 3899    }
 3900    #endregion
 3901
 3902    #region IArchiveStorage Members
 3903
 3904    /// <summary>
 3905    /// Gets a temporary output <see cref="Stream"/>
 3906    /// </summary>
 3907    /// <returns>Returns the temporary output stream.</returns>
 3908    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3909    public abstract Stream GetTemporaryOutput();
 3910
 3911    /// <summary>
 3912    /// Converts the temporary <see cref="Stream"/> to its final form.
 3913    /// </summary>
 3914    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 3915    /// the final storage for the archive.</returns>
 3916    /// <seealso cref="GetTemporaryOutput"/>
 3917    public abstract Stream ConvertTemporaryToFinal();
 3918
 3919    /// <summary>
 3920    /// Make a temporary copy of a <see cref="Stream"/>.
 3921    /// </summary>
 3922    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>
 3923    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3924    public abstract Stream MakeTemporaryCopy(Stream stream);
 3925
 3926    /// <summary>
 3927    /// Return a stream suitable for performing direct updates on the original source.
 3928    /// </summary>
 3929    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>
 3930    /// <returns>Returns a stream suitable for direct updating.</returns>
 3931    public abstract Stream OpenForDirectUpdate(Stream stream);
 3932
 3933    /// <summary>
 3934    /// Disposes this instance.
 3935    /// </summary>
 3936    public abstract void Dispose();
 3937
 3938    /// <summary>
 3939    /// Gets the update mode applicable.
 3940    /// </summary>
 3941    /// <value>The update mode.</value>
 3942    public FileUpdateMode UpdateMode {
 3943      get {
 3944        return updateMode_;
 3945      }
 3946    }
 3947
 3948    #endregion
 3949
 3950    #region Instance Fields
 3951    FileUpdateMode updateMode_;
 3952    #endregion
 3953  }
 3954
 3955  /// <summary>
 3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.
 3957  /// </summary>
 3958  public class DiskArchiveStorage : BaseArchiveStorage
 3959  {
 3960    #region Constructors
 3961    /// <summary>
 3962    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3963    /// </summary>
 3964    /// <param name="file">The file.</param>
 3965    /// <param name="updateMode">The update mode.</param>
 3966    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)
 3967      : base(updateMode)
 3968    {
 3969      if (file.Name == null) {
 3970        throw new ZipException("Cant handle non file archives");
 3971      }
 3972
 3973      fileName_ = file.Name;
 3974    }
 3975
 3976    /// <summary>
 3977    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3978    /// </summary>
 3979    /// <param name="file">The file.</param>
 3980    public DiskArchiveStorage(ZipFile file)
 3981      : this(file, FileUpdateMode.Safe)
 3982    {
 3983    }
 3984    #endregion
 3985
 3986    #region IArchiveStorage Members
 3987
 3988    /// <summary>
 3989    /// Gets a temporary output <see cref="Stream"/> for performing updates on.
 3990    /// </summary>
 3991    /// <returns>Returns the temporary output stream.</returns>
 3992    public override Stream GetTemporaryOutput()
 3993    {
 3994      if (temporaryName_ != null) {
 3995        temporaryName_ = GetTempFileName(temporaryName_, true);
 3996        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 3997      } else {
 3998        // Determine where to place files based on internal strategy.
 3999        // Currently this is always done in system temp directory.
 4000        temporaryName_ = Path.GetTempFileName();
 4001        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 4002      }
 4003
 4004      return temporaryStream_;
 4005    }
 4006
 4007    /// <summary>
 4008    /// Converts a temporary <see cref="Stream"/> to its final form.
 4009    /// </summary>
 4010    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4011    /// the final storage for the archive.</returns>
 4012    public override Stream ConvertTemporaryToFinal()
 4013    {
 4014      if (temporaryStream_ == null) {
 4015        throw new ZipException("No temporary stream has been created");
 4016      }
 4017
 4018      Stream result = null;
 4019
 4020      string moveTempName = GetTempFileName(fileName_, false);
 4021      bool newFileCreated = false;
 4022
 4023      try {
 4024        temporaryStream_.Close();
 4025        File.Move(fileName_, moveTempName);
 4026        File.Move(temporaryName_, fileName_);
 4027        newFileCreated = true;
 4028        File.Delete(moveTempName);
 4029
 4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 4031      } catch (Exception) {
 4032        result = null;
 4033
 4034        // Try to roll back changes...
 4035        if (!newFileCreated) {
 4036          File.Move(moveTempName, fileName_);
 4037          File.Delete(temporaryName_);
 4038        }
 4039
 4040        throw;
 4041      }
 4042
 4043      return result;
 4044    }
 4045
 4046    /// <summary>
 4047    /// Make a temporary copy of a stream.
 4048    /// </summary>
 4049    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4050    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4051    public override Stream MakeTemporaryCopy(Stream stream)
 4052    {
 4053      stream.Close();
 4054
 4055      temporaryName_ = GetTempFileName(fileName_, true);
 4056      File.Copy(fileName_, temporaryName_, true);
 4057
 4058      temporaryStream_ = new FileStream(temporaryName_,
 4059        FileMode.Open,
 4060        FileAccess.ReadWrite);
 4061      return temporaryStream_;
 4062    }
 4063
 4064    /// <summary>
 4065    /// Return a stream suitable for performing direct updates on the original source.
 4066    /// </summary>
 4067    /// <param name="stream">The current stream.</param>
 4068    /// <returns>Returns a stream suitable for direct updating.</returns>
 4069    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>
 4070    public override Stream OpenForDirectUpdate(Stream stream)
 4071    {
 4072      Stream result;
 4073      if ((stream == null) || !stream.CanWrite) {
 4074        if (stream != null) {
 4075          stream.Close();
 4076        }
 4077
 4078        result = new FileStream(fileName_,
 4079            FileMode.Open,
 4080            FileAccess.ReadWrite);
 4081      } else {
 4082        result = stream;
 4083      }
 4084
 4085      return result;
 4086    }
 4087
 4088    /// <summary>
 4089    /// Disposes this instance.
 4090    /// </summary>
 4091    public override void Dispose()
 4092    {
 4093      if (temporaryStream_ != null) {
 4094        temporaryStream_.Close();
 4095      }
 4096    }
 4097
 4098    #endregion
 4099
 4100    #region Internal routines
 4101    static string GetTempFileName(string original, bool makeTempFile)
 4102    {
 4103      string result = null;
 4104
 4105      if (original == null) {
 4106        result = Path.GetTempFileName();
 4107      } else {
 4108        int counter = 0;
 4109        int suffixSeed = DateTime.Now.Second;
 4110
 4111        while (result == null) {
 4112          counter += 1;
 4113          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);
 4114          if (!File.Exists(newName)) {
 4115            if (makeTempFile) {
 4116              try {
 4117                // Try and create the file.
 4118                using (FileStream stream = File.Create(newName)) {
 4119                }
 4120                result = newName;
 4121              } catch {
 4122                suffixSeed = DateTime.Now.Second;
 4123              }
 4124            } else {
 4125              result = newName;
 4126            }
 4127          }
 4128        }
 4129      }
 4130      return result;
 4131    }
 4132    #endregion
 4133
 4134    #region Instance Fields
 4135    Stream temporaryStream_;
 4136    string fileName_;
 4137    string temporaryName_;
 4138    #endregion
 4139  }
 4140
 4141  /// <summary>
 4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.
 4143  /// </summary>
 4144  public class MemoryArchiveStorage : BaseArchiveStorage
 4145  {
 4146    #region Constructors
 4147    /// <summary>
 4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4149    /// </summary>
 4150    public MemoryArchiveStorage()
 4151      : base(FileUpdateMode.Direct)
 4152    {
 4153    }
 4154
 4155    /// <summary>
 4156    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4157    /// </summary>
 4158    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>
 4159    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>
 4160    public MemoryArchiveStorage(FileUpdateMode updateMode)
 4161      : base(updateMode)
 4162    {
 4163    }
 4164
 4165    #endregion
 4166
 4167    #region Properties
 4168    /// <summary>
 4169    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.
 4170    /// </summary>
 4171    public MemoryStream FinalStream {
 4172      get { return finalStream_; }
 4173    }
 4174
 4175    #endregion
 4176
 4177    #region IArchiveStorage Members
 4178
 4179    /// <summary>
 4180    /// Gets the temporary output <see cref="Stream"/>
 4181    /// </summary>
 4182    /// <returns>Returns the temporary output stream.</returns>
 4183    public override Stream GetTemporaryOutput()
 4184    {
 4185      temporaryStream_ = new MemoryStream();
 4186      return temporaryStream_;
 4187    }
 4188
 4189    /// <summary>
 4190    /// Converts the temporary <see cref="Stream"/> to its final form.
 4191    /// </summary>
 4192    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4193    /// the final storage for the archive.</returns>
 4194    public override Stream ConvertTemporaryToFinal()
 4195    {
 4196      if (temporaryStream_ == null) {
 4197        throw new ZipException("No temporary stream has been created");
 4198      }
 4199
 4200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());
 4201      return finalStream_;
 4202    }
 4203
 4204    /// <summary>
 4205    /// Make a temporary copy of the original stream.
 4206    /// </summary>
 4207    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4208    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4209    public override Stream MakeTemporaryCopy(Stream stream)
 4210    {
 4211      temporaryStream_ = new MemoryStream();
 4212      stream.Position = 0;
 4213      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);
 4214      return temporaryStream_;
 4215    }
 4216
 4217    /// <summary>
 4218    /// Return a stream suitable for performing direct updates on the original source.
 4219    /// </summary>
 4220    /// <param name="stream">The original source stream</param>
 4221    /// <returns>Returns a stream suitable for direct updating.</returns>
 4222    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;
 4223    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>
 4224    public override Stream OpenForDirectUpdate(Stream stream)
 4225    {
 4226      Stream result;
 4227      if ((stream == null) || !stream.CanWrite) {
 4228
 4229        result = new MemoryStream();
 4230
 4231        if (stream != null) {
 4232          stream.Position = 0;
 4233          StreamUtils.Copy(stream, result, new byte[4096]);
 4234
 4235          stream.Close();
 4236        }
 4237      } else {
 4238        result = stream;
 4239      }
 4240
 4241      return result;
 4242    }
 4243
 4244    /// <summary>
 4245    /// Disposes this instance.
 4246    /// </summary>
 4247    public override void Dispose()
 4248    {
 4249      if (temporaryStream_ != null) {
 4250        temporaryStream_.Close();
 4251      }
 4252    }
 4253
 4254    #endregion
 4255
 4256    #region Instance Fields
 4257    MemoryStream temporaryStream_;
 4258    MemoryStream finalStream_;
 4259    #endregion
 4260  }
 4261
 4262  #endregion
 4263}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_StreamManipulator.htm b/docs/opencover/ICSharpCode.SharpZipLib_StreamManipulator.htm new file mode 100644 index 000000000..51145b39a --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_StreamManipulator.htm @@ -0,0 +1,289 @@ + + + + +ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\StreamManipulator.cs
Covered lines:51
Uncovered lines:12
Coverable lines:63
Total lines:241
Line coverage:80.9%
Branch coverage:67.6%
+

Metrics

+ + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
PeekBits(...)3100100
DropBits(...)1100100
GetBits(...)200
SkipToByteBoundary()1100100
CopyBytes(...)886.3680
Reset()1100100
SetInput(...)872.2260
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\StreamManipulator.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
 4{
 5  /// <summary>
 6  /// This class allows us to retrieve a specified number of bits from
 7  /// the input buffer, as well as copy big byte blocks.
 8  ///
 9  /// It uses an int buffer to store up to 31 bits for direct
 10  /// manipulation.  This guarantees that we can get at least 16 bits,
 11  /// but we only need at most 15, so this is all safe.
 12  ///
 13  /// There are some optimizations in this class, for example, you must
 14  /// never peek more than 8 bits more than needed, and you must first
 15  /// peek bits before you may drop them.  This is not a general purpose
 16  /// class but optimized for the behaviour of the Inflater.
 17  ///
 18  /// authors of the original java version : John Leuner, Jochen Hoenicke
 19  /// </summary>
 20  public class StreamManipulator
 21  {
 22    /// <summary>
 23    /// Get the next sequence of bits but don't increase input pointer.  bitCount must be
 24    /// less or equal 16 and if this call succeeds, you must drop
 25    /// at least n - 8 bits in the next call.
 26    /// </summary>
 27    /// <param name="bitCount">The number of bits to peek.</param>
 28    /// <returns>
 29    /// the value of the bits, or -1 if not enough bits available.  */
 30    /// </returns>
 31    public int PeekBits(int bitCount)
 32    {
 1162033       if (bitsInBuffer_ < bitCount) {
 628734         if (windowStart_ == windowEnd_) {
 39635          return -1; // ok
 36        }
 589137        buffer_ |= (uint)((window_[windowStart_++] & 0xff |
 589138                 (window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_);
 589139        bitsInBuffer_ += 16;
 40      }
 1122441      return (int)(buffer_ & ((1 << bitCount) - 1));
 42    }
 43
 44    /// <summary>
 45    /// Drops the next n bits from the input.  You should have called PeekBits
 46    /// with a bigger or equal n before, to make sure that enough bits are in
 47    /// the bit buffer.
 48    /// </summary>
 49    /// <param name="bitCount">The number of bits to drop.</param>
 50    public void DropBits(int bitCount)
 51    {
 1122452      buffer_ >>= bitCount;
 1122453      bitsInBuffer_ -= bitCount;
 1122454    }
 55
 56    /// <summary>
 57    /// Gets the next n bits and increases input pointer.  This is equivalent
 58    /// to <see cref="PeekBits"/> followed by <see cref="DropBits"/>, except for correct error handling.
 59    /// </summary>
 60    /// <param name="bitCount">The number of bits to retrieve.</param>
 61    /// <returns>
 62    /// the value of the bits, or -1 if not enough bits available.
 63    /// </returns>
 64    public int GetBits(int bitCount)
 65    {
 066      int bits = PeekBits(bitCount);
 067       if (bits >= 0) {
 068        DropBits(bitCount);
 69      }
 070      return bits;
 71    }
 72
 73    /// <summary>
 74    /// Gets the number of bits available in the bit buffer.  This must be
 75    /// only called when a previous PeekBits() returned -1.
 76    /// </summary>
 77    /// <returns>
 78    /// the number of bits available.
 79    /// </returns>
 80    public int AvailableBits {
 81      get {
 2382        return bitsInBuffer_;
 83      }
 84    }
 85
 86    /// <summary>
 87    /// Gets the number of bytes available.
 88    /// </summary>
 89    /// <returns>
 90    /// The number of bytes available.
 91    /// </returns>
 92    public int AvailableBytes {
 93      get {
 232794        return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3);
 95      }
 96    }
 97
 98    /// <summary>
 99    /// Skips to the next byte boundary.
 100    /// </summary>
 101    public void SkipToByteBoundary()
 102    {
 303103      buffer_ >>= (bitsInBuffer_ & 7);
 303104      bitsInBuffer_ &= ~7;
 303105    }
 106
 107    /// <summary>
 108    /// Returns true when SetInput can be called
 109    /// </summary>
 110    public bool IsNeedingInput {
 111      get {
 3355112        return windowStart_ == windowEnd_;
 113      }
 114    }
 115
 116    /// <summary>
 117    /// Copies bytes from input buffer to output buffer starting
 118    /// at output[offset].  You have to make sure, that the buffer is
 119    /// byte aligned.  If not enough bytes are available, copies fewer
 120    /// bytes.
 121    /// </summary>
 122    /// <param name="output">
 123    /// The buffer to copy bytes to.
 124    /// </param>
 125    /// <param name="offset">
 126    /// The offset in the buffer at which copying starts
 127    /// </param>
 128    /// <param name="length">
 129    /// The length to copy, 0 is allowed.
 130    /// </param>
 131    /// <returns>
 132    /// The number of bytes copied, 0 if no bytes were available.
 133    /// </returns>
 134    /// <exception cref="ArgumentOutOfRangeException">
 135    /// Length is less than zero
 136    /// </exception>
 137    /// <exception cref="InvalidOperationException">
 138    /// Bit buffer isnt byte aligned
 139    /// </exception>
 140    public int CopyBytes(byte[] output, int offset, int length)
 141    {
 2376142       if (length < 0) {
 0143        throw new ArgumentOutOfRangeException(nameof(length));
 144      }
 145
 2376146       if ((bitsInBuffer_ & 7) != 0) {
 147        // bits_in_buffer may only be 0 or a multiple of 8
 0148        throw new InvalidOperationException("Bit buffer is not byte aligned!");
 149      }
 150
 2376151      int count = 0;
 2600152       while ((bitsInBuffer_ > 0) && (length > 0)) {
 224153        output[offset++] = (byte)buffer_;
 224154        buffer_ >>= 8;
 224155        bitsInBuffer_ -= 8;
 224156        length--;
 224157        count++;
 158      }
 159
 2376160       if (length == 0) {
 996161        return count;
 162      }
 163
 1380164      int avail = windowEnd_ - windowStart_;
 1380165       if (length > avail) {
 0166        length = avail;
 167      }
 1380168      System.Array.Copy(window_, windowStart_, output, offset, length);
 1380169      windowStart_ += length;
 170
 1380171       if (((windowStart_ - windowEnd_) & 1) != 0) {
 172        // We always want an even number of bytes in input, see peekBits
 210173        buffer_ = (uint)(window_[windowStart_++] & 0xff);
 210174        bitsInBuffer_ = 8;
 175      }
 1380176      return count + length;
 177    }
 178
 179    /// <summary>
 180    /// Resets state and empties internal buffers
 181    /// </summary>
 182    public void Reset()
 183    {
 41184      buffer_ = 0;
 41185      windowStart_ = windowEnd_ = bitsInBuffer_ = 0;
 41186    }
 187
 188    /// <summary>
 189    /// Add more input for consumption.
 190    /// Only call when IsNeedingInput returns true
 191    /// </summary>
 192    /// <param name="buffer">data to be input</param>
 193    /// <param name="offset">offset of first byte of input</param>
 194    /// <param name="count">number of bytes of input to add.</param>
 195    public void SetInput(byte[] buffer, int offset, int count)
 196    {
 1433197       if (buffer == null) {
 0198        throw new ArgumentNullException(nameof(buffer));
 199      }
 200
 1433201       if (offset < 0) {
 0202        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");
 203      }
 204
 1433205       if (count < 0) {
 0206        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");
 207      }
 208
 1433209       if (windowStart_ < windowEnd_) {
 0210        throw new InvalidOperationException("Old input was not completely processed");
 211      }
 212
 1433213      int end = offset + count;
 214
 215      // We want to throw an ArrayIndexOutOfBoundsException early.
 216      // Note the check also handles integer wrap around.
 1433217       if ((offset > end) || (end > buffer.Length)) {
 0218        throw new ArgumentOutOfRangeException(nameof(count));
 219      }
 220
 1433221       if ((count & 1) != 0) {
 222        // We always want an even number of bytes in input, see PeekBits
 214223        buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_);
 214224        bitsInBuffer_ += 8;
 225      }
 226
 1433227      window_ = buffer;
 1433228      windowStart_ = offset;
 1433229      windowEnd_ = end;
 1433230    }
 231
 232    #region Instance Fields
 233    private byte[] window_;
 234    private int windowStart_;
 235    private int windowEnd_;
 236
 237    private uint buffer_;
 238    private int bitsInBuffer_;
 239    #endregion
 240  }
 241}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_StreamUtils.htm b/docs/opencover/ICSharpCode.SharpZipLib_StreamUtils.htm new file mode 100644 index 000000000..dbc5102fb --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_StreamUtils.htm @@ -0,0 +1,255 @@ + + + + +ICSharpCode.SharpZipLib.Core.StreamUtils - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.StreamUtils
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\StreamUtils.cs
Covered lines:25
Uncovered lines:53
Coverable lines:78
Total lines:208
Line coverage:32%
Branch coverage:34%
+

Metrics

+ + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
ReadFully(...)1100100
ReadFully(...)966.6758.82
Copy(...)776.4769.23
Copy(...)100
Copy(...)1200
.ctor()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\StreamUtils.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Core
 5{
 6  /// <summary>
 7  /// Provides simple <see cref="Stream"/>" utilities.
 8  /// </summary>
 9  public sealed class StreamUtils
 10  {
 11    /// <summary>
 12    /// Read from a <see cref="Stream"/> ensuring all the required data is read.
 13    /// </summary>
 14    /// <param name="stream">The stream to read.</param>
 15    /// <param name="buffer">The buffer to fill.</param>
 16    /// <seealso cref="ReadFully(Stream,byte[],int,int)"/>
 17    static public void ReadFully(Stream stream, byte[] buffer)
 18    {
 26378919      ReadFully(stream, buffer, 0, buffer.Length);
 26378920    }
 21
 22    /// <summary>
 23    /// Read from a <see cref="Stream"/>" ensuring all the required data is read.
 24    /// </summary>
 25    /// <param name="stream">The stream to read data from.</param>
 26    /// <param name="buffer">The buffer to store data in.</param>
 27    /// <param name="offset">The offset at which to begin storing data.</param>
 28    /// <param name="count">The number of bytes of data to store.</param>
 29    /// <exception cref="ArgumentNullException">Required parameter is null</exception>
 30    /// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> and or <paramref name="count"/> are inva
 31    /// <exception cref="EndOfStreamException">End of stream is encountered before all the data has been read.</exceptio
 32    static public void ReadFully(Stream stream, byte[] buffer, int offset, int count)
 33    {
 32974534       if (stream == null) {
 035        throw new ArgumentNullException(nameof(stream));
 36      }
 37
 32974538       if (buffer == null) {
 039        throw new ArgumentNullException(nameof(buffer));
 40      }
 41
 42      // Offset can equal length when buffer and count are 0.
 32974543       if ((offset < 0) || (offset > buffer.Length)) {
 044        throw new ArgumentOutOfRangeException(nameof(offset));
 45      }
 46
 32974547       if ((count < 0) || (offset + count > buffer.Length)) {
 048        throw new ArgumentOutOfRangeException(nameof(count));
 49      }
 50
 52767851       while (count > 0) {
 19793352        int readCount = stream.Read(buffer, offset, count);
 19793353         if (readCount <= 0) {
 054          throw new EndOfStreamException();
 55        }
 19793356        offset += readCount;
 19793357        count -= readCount;
 58      }
 32974559    }
 60
 61    /// <summary>
 62    /// Copy the contents of one <see cref="Stream"/> to another.
 63    /// </summary>
 64    /// <param name="source">The stream to source data from.</param>
 65    /// <param name="destination">The stream to write data to.</param>
 66    /// <param name="buffer">The buffer to use during copying.</param>
 67    static public void Copy(Stream source, Stream destination, byte[] buffer)
 68    {
 869       if (source == null) {
 070        throw new ArgumentNullException(nameof(source));
 71      }
 72
 873       if (destination == null) {
 074        throw new ArgumentNullException(nameof(destination));
 75      }
 76
 877       if (buffer == null) {
 078        throw new ArgumentNullException(nameof(buffer));
 79      }
 80
 81      // Ensure a reasonable size of buffer is used without being prohibitive.
 882       if (buffer.Length < 128) {
 083        throw new ArgumentException("Buffer is too small", nameof(buffer));
 84      }
 85
 886      bool copying = true;
 87
 2488       while (copying) {
 1689        int bytesRead = source.Read(buffer, 0, buffer.Length);
 1690         if (bytesRead > 0) {
 891          destination.Write(buffer, 0, bytesRead);
 892        } else {
 893          destination.Flush();
 894          copying = false;
 95        }
 96      }
 897    }
 98
 99    /// <summary>
 100    /// Copy the contents of one <see cref="Stream"/> to another.
 101    /// </summary>
 102    /// <param name="source">The stream to source data from.</param>
 103    /// <param name="destination">The stream to write data to.</param>
 104    /// <param name="buffer">The buffer to use during copying.</param>
 105    /// <param name="progressHandler">The <see cref="ProgressHandler">progress handler delegate</see> to use.</param>
 106    /// <param name="updateInterval">The minimum <see cref="TimeSpan"/> between progress updates.</param>
 107    /// <param name="sender">The source for this event.</param>
 108    /// <param name="name">The name to use with the event.</param>
 109    /// <remarks>This form is specialised for use within #Zip to support events during archive operations.</remarks>
 110    static public void Copy(Stream source, Stream destination,
 111      byte[] buffer, ProgressHandler progressHandler, TimeSpan updateInterval, object sender, string name)
 112    {
 0113      Copy(source, destination, buffer, progressHandler, updateInterval, sender, name, -1);
 0114    }
 115
 116    /// <summary>
 117    /// Copy the contents of one <see cref="Stream"/> to another.
 118    /// </summary>
 119    /// <param name="source">The stream to source data from.</param>
 120    /// <param name="destination">The stream to write data to.</param>
 121    /// <param name="buffer">The buffer to use during copying.</param>
 122    /// <param name="progressHandler">The <see cref="ProgressHandler">progress handler delegate</see> to use.</param>
 123    /// <param name="updateInterval">The minimum <see cref="TimeSpan"/> between progress updates.</param>
 124    /// <param name="sender">The source for this event.</param>
 125    /// <param name="name">The name to use with the event.</param>
 126    /// <param name="fixedTarget">A predetermined fixed target value to use with progress updates.
 127    /// If the value is negative the target is calculated by looking at the stream.</param>
 128    /// <remarks>This form is specialised for use within #Zip to support events during archive operations.</remarks>
 129    static public void Copy(Stream source, Stream destination,
 130      byte[] buffer,
 131      ProgressHandler progressHandler, TimeSpan updateInterval,
 132      object sender, string name, long fixedTarget)
 133    {
 0134       if (source == null) {
 0135        throw new ArgumentNullException(nameof(source));
 136      }
 137
 0138       if (destination == null) {
 0139        throw new ArgumentNullException(nameof(destination));
 140      }
 141
 0142       if (buffer == null) {
 0143        throw new ArgumentNullException(nameof(buffer));
 144      }
 145
 146      // Ensure a reasonable size of buffer is used without being prohibitive.
 0147       if (buffer.Length < 128) {
 0148        throw new ArgumentException("Buffer is too small", nameof(buffer));
 149      }
 150
 0151       if (progressHandler == null) {
 0152        throw new ArgumentNullException(nameof(progressHandler));
 153      }
 154
 0155      bool copying = true;
 156
 0157      DateTime marker = DateTime.Now;
 0158      long processed = 0;
 0159      long target = 0;
 160
 0161       if (fixedTarget >= 0) {
 0162        target = fixedTarget;
 0163       } else if (source.CanSeek) {
 0164        target = source.Length - source.Position;
 165      }
 166
 167      // Always fire 0% progress..
 0168      var args = new ProgressEventArgs(name, processed, target);
 0169      progressHandler(sender, args);
 170
 0171      bool progressFired = true;
 172
 0173       while (copying) {
 0174        int bytesRead = source.Read(buffer, 0, buffer.Length);
 0175         if (bytesRead > 0) {
 0176          processed += bytesRead;
 0177          progressFired = false;
 0178          destination.Write(buffer, 0, bytesRead);
 0179        } else {
 0180          destination.Flush();
 0181          copying = false;
 182        }
 183
 0184         if (DateTime.Now - marker > updateInterval) {
 0185          progressFired = true;
 0186          marker = DateTime.Now;
 0187          args = new ProgressEventArgs(name, processed, target);
 0188          progressHandler(sender, args);
 189
 0190          copying = args.ContinueRunning;
 191        }
 192      }
 193
 0194       if (!progressFired) {
 0195        args = new ProgressEventArgs(name, processed, target);
 0196        progressHandler(sender, args);
 197      }
 0198    }
 199
 200    /// <summary>
 201    /// Initialise an instance of <see cref="StreamUtils"></see>
 202    /// </summary>
 0203    private StreamUtils()
 204    {
 205      // Do nothing.
 0206    }
 207  }
 208}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_TarArchive.htm b/docs/opencover/ICSharpCode.SharpZipLib_TarArchive.htm new file mode 100644 index 000000000..c29f49847 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_TarArchive.htm @@ -0,0 +1,894 @@ + + + + +ICSharpCode.SharpZipLib.Tar.TarArchive - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Tar.TarArchive
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarArchive.cs
Covered lines:46
Uncovered lines:223
Coverable lines:269
Total lines:830
Line coverage:17.1%
Branch coverage:13.6%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
OnProgressMessageEvent(...)200
.ctor()100
.ctor(...)285.7166.67
.ctor(...)285.7166.67
CreateInputTarArchive(...)362.560
CreateInputTarArchive(...)36060
CreateOutputTarArchive(...)362.560
CreateOutputTarArchive(...)36060
SetKeepOldFiles(...)200
SetAsciiTranslation(...)200
SetUserInfo(...)200
CloseArchive()100
ListContents()357.1460
ExtractContents(...)500
ExtractEntry(...)1400
WriteEntry(...)500
WriteEntryCore(...)1900
Dispose()1100100
Dispose(...)510077.78
Close()100
Finalize()100
EnsureDirectoryExists(...)200
IsBinary(...)700
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarArchive.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Text;
 4
 5namespace ICSharpCode.SharpZipLib.Tar
 6{
 7  /// <summary>
 8  /// Used to advise clients of 'events' while processing archives
 9  /// </summary>
 10  public delegate void ProgressMessageHandler(TarArchive archive, TarEntry entry, string message);
 11
 12  /// <summary>
 13  /// The TarArchive class implements the concept of a
 14  /// 'Tape Archive'. A tar archive is a series of entries, each of
 15  /// which represents a file system object. Each entry in
 16  /// the archive consists of a header block followed by 0 or more data blocks.
 17  /// Directory entries consist only of the header block, and are followed by entries
 18  /// for the directory's contents. File entries consist of a
 19  /// header followed by the number of blocks needed to
 20  /// contain the file's contents. All entries are written on
 21  /// block boundaries. Blocks are 512 bytes long.
 22  ///
 23  /// TarArchives are instantiated in either read or write mode,
 24  /// based upon whether they are instantiated with an InputStream
 25  /// or an OutputStream. Once instantiated TarArchives read/write
 26  /// mode can not be changed.
 27  ///
 28  /// There is currently no support for random access to tar archives.
 29  /// However, it seems that subclassing TarArchive, and using the
 30  /// TarBuffer.CurrentRecord and TarBuffer.CurrentBlock
 31  /// properties, this would be rather trivial.
 32  /// </summary>
 33  public class TarArchive : IDisposable
 34  {
 35    /// <summary>
 36    /// Client hook allowing detailed information to be reported during processing
 37    /// </summary>
 38    public event ProgressMessageHandler ProgressMessageEvent;
 39
 40    /// <summary>
 41    /// Raises the ProgressMessage event
 42    /// </summary>
 43    /// <param name="entry">The <see cref="TarEntry">TarEntry</see> for this event</param>
 44    /// <param name="message">message for this event.  Null is no message</param>
 45    protected virtual void OnProgressMessageEvent(TarEntry entry, string message)
 46    {
 047      ProgressMessageHandler handler = ProgressMessageEvent;
 048       if (handler != null) {
 049        handler(this, entry, message);
 50      }
 051    }
 52
 53    #region Constructors
 54    /// <summary>
 55    /// Constructor for a default <see cref="TarArchive"/>.
 56    /// </summary>
 057    protected TarArchive()
 58    {
 059    }
 60
 61    /// <summary>
 62    /// Initalise a TarArchive for input.
 63    /// </summary>
 64    /// <param name="stream">The <see cref="TarInputStream"/> to use for input.</param>
 165    protected TarArchive(TarInputStream stream)
 66    {
 167       if (stream == null) {
 068        throw new ArgumentNullException(nameof(stream));
 69      }
 70
 171      tarIn = stream;
 172    }
 73
 74    /// <summary>
 75    /// Initialise a TarArchive for output.
 76    /// </summary>
 77    /// <param name="stream">The <see cref="TarOutputStream"/> to use for output.</param>
 178    protected TarArchive(TarOutputStream stream)
 79    {
 180       if (stream == null) {
 081        throw new ArgumentNullException(nameof(stream));
 82      }
 83
 184      tarOut = stream;
 185    }
 86    #endregion
 87
 88    #region Static factory methods
 89    /// <summary>
 90    /// The InputStream based constructors create a TarArchive for the
 91    /// purposes of extracting or listing a tar archive. Thus, use
 92    /// these constructors when you wish to extract files from or list
 93    /// the contents of an existing tar archive.
 94    /// </summary>
 95    /// <param name="inputStream">The stream to retrieve archive data from.</param>
 96    /// <returns>Returns a new <see cref="TarArchive"/> suitable for reading from.</returns>
 97    public static TarArchive CreateInputTarArchive(Stream inputStream)
 98    {
 199       if (inputStream == null) {
 0100        throw new ArgumentNullException(nameof(inputStream));
 101      }
 102
 1103      var tarStream = inputStream as TarInputStream;
 104
 105      TarArchive result;
 1106       if (tarStream != null) {
 0107        result = new TarArchive(tarStream);
 0108      } else {
 1109        result = CreateInputTarArchive(inputStream, TarBuffer.DefaultBlockFactor);
 110      }
 1111      return result;
 112    }
 113
 114    /// <summary>
 115    /// Create TarArchive for reading setting block factor
 116    /// </summary>
 117    /// <param name="inputStream">A stream containing the tar archive contents</param>
 118    /// <param name="blockFactor">The blocking factor to apply</param>
 119    /// <returns>Returns a <see cref="TarArchive"/> suitable for reading.</returns>
 120    public static TarArchive CreateInputTarArchive(Stream inputStream, int blockFactor)
 121    {
 1122       if (inputStream == null) {
 0123        throw new ArgumentNullException(nameof(inputStream));
 124      }
 125
 1126       if (inputStream is TarInputStream) {
 0127        throw new ArgumentException("TarInputStream not valid");
 128      }
 129
 1130      return new TarArchive(new TarInputStream(inputStream, blockFactor));
 131    }
 132
 133    /// <summary>
 134    /// Create a TarArchive for writing to, using the default blocking factor
 135    /// </summary>
 136    /// <param name="outputStream">The <see cref="Stream"/> to write to</param>
 137    /// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>
 138    public static TarArchive CreateOutputTarArchive(Stream outputStream)
 139    {
 1140       if (outputStream == null) {
 0141        throw new ArgumentNullException(nameof(outputStream));
 142      }
 143
 1144      var tarStream = outputStream as TarOutputStream;
 145
 146      TarArchive result;
 1147       if (tarStream != null) {
 0148        result = new TarArchive(tarStream);
 0149      } else {
 1150        result = CreateOutputTarArchive(outputStream, TarBuffer.DefaultBlockFactor);
 151      }
 1152      return result;
 153    }
 154
 155    /// <summary>
 156    /// Create a <see cref="TarArchive">tar archive</see> for writing.
 157    /// </summary>
 158    /// <param name="outputStream">The stream to write to</param>
 159    /// <param name="blockFactor">The blocking factor to use for buffering.</param>
 160    /// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>
 161    public static TarArchive CreateOutputTarArchive(Stream outputStream, int blockFactor)
 162    {
 1163       if (outputStream == null) {
 0164        throw new ArgumentNullException(nameof(outputStream));
 165      }
 166
 1167       if (outputStream is TarOutputStream) {
 0168        throw new ArgumentException("TarOutputStream is not valid");
 169      }
 170
 1171      return new TarArchive(new TarOutputStream(outputStream, blockFactor));
 172    }
 173    #endregion
 174
 175    /// <summary>
 176    /// Set the flag that determines whether existing files are
 177    /// kept, or overwritten during extraction.
 178    /// </summary>
 179    /// <param name="keepExistingFiles">
 180    /// If true, do not overwrite existing files.
 181    /// </param>
 182    public void SetKeepOldFiles(bool keepExistingFiles)
 183    {
 0184       if (isDisposed) {
 0185        throw new ObjectDisposedException("TarArchive");
 186      }
 187
 0188      keepOldFiles = keepExistingFiles;
 0189    }
 190
 191    /// <summary>
 192    /// Get/set the ascii file translation flag. If ascii file translation
 193    /// is true, then the file is checked to see if it a binary file or not.
 194    /// If the flag is true and the test indicates it is ascii text
 195    /// file, it will be translated. The translation converts the local
 196    /// operating system's concept of line ends into the UNIX line end,
 197    /// '\n', which is the defacto standard for a TAR archive. This makes
 198    /// text files compatible with UNIX.
 199    /// </summary>
 200    public bool AsciiTranslate {
 201      get {
 0202         if (isDisposed) {
 0203          throw new ObjectDisposedException("TarArchive");
 204        }
 205
 0206        return asciiTranslate;
 207      }
 208
 209      set {
 0210         if (isDisposed) {
 0211          throw new ObjectDisposedException("TarArchive");
 212        }
 213
 0214        asciiTranslate = value;
 0215      }
 216
 217    }
 218
 219    /// <summary>
 220    /// Set the ascii file translation flag.
 221    /// </summary>
 222    /// <param name= "translateAsciiFiles">
 223    /// If true, translate ascii text files.
 224    /// </param>
 225    [Obsolete("Use the AsciiTranslate property")]
 226    public void SetAsciiTranslation(bool translateAsciiFiles)
 227    {
 0228       if (isDisposed) {
 0229        throw new ObjectDisposedException("TarArchive");
 230      }
 231
 0232      asciiTranslate = translateAsciiFiles;
 0233    }
 234
 235    /// <summary>
 236    /// PathPrefix is added to entry names as they are written if the value is not null.
 237    /// A slash character is appended after PathPrefix
 238    /// </summary>
 239    public string PathPrefix {
 240      get {
 0241         if (isDisposed) {
 0242          throw new ObjectDisposedException("TarArchive");
 243        }
 244
 0245        return pathPrefix;
 246      }
 247
 248      set {
 0249         if (isDisposed) {
 0250          throw new ObjectDisposedException("TarArchive");
 251        }
 252
 0253        pathPrefix = value;
 0254      }
 255
 256    }
 257
 258    /// <summary>
 259    /// RootPath is removed from entry names if it is found at the
 260    /// beginning of the name.
 261    /// </summary>
 262    public string RootPath {
 263      get {
 0264         if (isDisposed) {
 0265          throw new ObjectDisposedException("TarArchive");
 266        }
 267
 0268        return rootPath;
 269      }
 270
 271      set {
 0272         if (isDisposed) {
 0273          throw new ObjectDisposedException("TarArchive");
 274        }
 275        // Convert to forward slashes for matching. Trim trailing / for correct final path
 0276        rootPath = value.Replace('\\', '/').TrimEnd('/');
 0277      }
 278    }
 279
 280    /// <summary>
 281    /// Set user and group information that will be used to fill in the
 282    /// tar archive's entry headers. This information is based on that available
 283    /// for the linux operating system, which is not always available on other
 284    /// operating systems.  TarArchive allows the programmer to specify values
 285    /// to be used in their place.
 286    /// <see cref="ApplyUserInfoOverrides"/> is set to true by this call.
 287    /// </summary>
 288    /// <param name="userId">
 289    /// The user id to use in the headers.
 290    /// </param>
 291    /// <param name="userName">
 292    /// The user name to use in the headers.
 293    /// </param>
 294    /// <param name="groupId">
 295    /// The group id to use in the headers.
 296    /// </param>
 297    /// <param name="groupName">
 298    /// The group name to use in the headers.
 299    /// </param>
 300    public void SetUserInfo(int userId, string userName, int groupId, string groupName)
 301    {
 0302       if (isDisposed) {
 0303        throw new ObjectDisposedException("TarArchive");
 304      }
 305
 0306      this.userId = userId;
 0307      this.userName = userName;
 0308      this.groupId = groupId;
 0309      this.groupName = groupName;
 0310      applyUserInfoOverrides = true;
 0311    }
 312
 313    /// <summary>
 314    /// Get or set a value indicating if overrides defined by <see cref="SetUserInfo">SetUserInfo</see> should be applie
 315    /// </summary>
 316    /// <remarks>If overrides are not applied then the values as set in each header will be used.</remarks>
 317    public bool ApplyUserInfoOverrides {
 318      get {
 0319         if (isDisposed) {
 0320          throw new ObjectDisposedException("TarArchive");
 321        }
 322
 0323        return applyUserInfoOverrides;
 324      }
 325
 326      set {
 0327         if (isDisposed) {
 0328          throw new ObjectDisposedException("TarArchive");
 329        }
 330
 0331        applyUserInfoOverrides = value;
 0332      }
 333    }
 334
 335    /// <summary>
 336    /// Get the archive user id.
 337    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
 338    /// on how to allow setting values on a per entry basis.
 339    /// </summary>
 340    /// <returns>
 341    /// The current user id.
 342    /// </returns>
 343    public int UserId {
 344      get {
 0345         if (isDisposed) {
 0346          throw new ObjectDisposedException("TarArchive");
 347        }
 348
 0349        return userId;
 350      }
 351    }
 352
 353    /// <summary>
 354    /// Get the archive user name.
 355    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
 356    /// on how to allow setting values on a per entry basis.
 357    /// </summary>
 358    /// <returns>
 359    /// The current user name.
 360    /// </returns>
 361    public string UserName {
 362      get {
 0363         if (isDisposed) {
 0364          throw new ObjectDisposedException("TarArchive");
 365        }
 366
 0367        return userName;
 368      }
 369    }
 370
 371    /// <summary>
 372    /// Get the archive group id.
 373    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
 374    /// on how to allow setting values on a per entry basis.
 375    /// </summary>
 376    /// <returns>
 377    /// The current group id.
 378    /// </returns>
 379    public int GroupId {
 380      get {
 0381         if (isDisposed) {
 0382          throw new ObjectDisposedException("TarArchive");
 383        }
 384
 0385        return groupId;
 386      }
 387    }
 388
 389    /// <summary>
 390    /// Get the archive group name.
 391    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
 392    /// on how to allow setting values on a per entry basis.
 393    /// </summary>
 394    /// <returns>
 395    /// The current group name.
 396    /// </returns>
 397    public string GroupName {
 398      get {
 0399         if (isDisposed) {
 0400          throw new ObjectDisposedException("TarArchive");
 401        }
 402
 0403        return groupName;
 404      }
 405    }
 406
 407    /// <summary>
 408    /// Get the archive's record size. Tar archives are composed of
 409    /// a series of RECORDS each containing a number of BLOCKS.
 410    /// This allowed tar archives to match the IO characteristics of
 411    /// the physical device being used. Archives are expected
 412    /// to be properly "blocked".
 413    /// </summary>
 414    /// <returns>
 415    /// The record size this archive is using.
 416    /// </returns>
 417    public int RecordSize {
 418      get {
 1419         if (isDisposed) {
 0420          throw new ObjectDisposedException("TarArchive");
 421        }
 422
 1423         if (tarIn != null) {
 0424          return tarIn.RecordSize;
 1425         } else if (tarOut != null) {
 1426          return tarOut.RecordSize;
 427        }
 0428        return TarBuffer.DefaultRecordSize;
 429      }
 430    }
 431
 432    /// <summary>
 433    /// Sets the IsStreamOwner property on the underlying stream.
 434    /// Set this to false to prevent the Close of the TarArchive from closing the stream.
 435    /// </summary>
 436    public bool IsStreamOwner {
 437      set {
 0438         if (tarIn != null) {
 0439          tarIn.IsStreamOwner = value;
 0440        } else {
 0441          tarOut.IsStreamOwner = value;
 442        }
 0443      }
 444    }
 445
 446    /// <summary>
 447    /// Close the archive.
 448    /// </summary>
 449    [Obsolete("Use Close instead")]
 450    public void CloseArchive()
 451    {
 0452      Close();
 0453    }
 454
 455    /// <summary>
 456    /// Perform the "list" command for the archive contents.
 457    ///
 458    /// NOTE That this method uses the <see cref="ProgressMessageEvent"> progress event</see> to actually list
 459    /// the contents. If the progress display event is not set, nothing will be listed!
 460    /// </summary>
 461    public void ListContents()
 462    {
 1463       if (isDisposed) {
 0464        throw new ObjectDisposedException("TarArchive");
 465      }
 466
 0467      while (true) {
 1468        TarEntry entry = tarIn.GetNextEntry();
 469
 1470         if (entry == null) {
 471          break;
 472        }
 0473        OnProgressMessageEvent(entry, null);
 474      }
 1475    }
 476
 477    /// <summary>
 478    /// Perform the "extract" command and extract the contents of the archive.
 479    /// </summary>
 480    /// <param name="destinationDirectory">
 481    /// The destination directory into which to extract.
 482    /// </param>
 483    public void ExtractContents(string destinationDirectory)
 484    {
 0485       if (isDisposed) {
 0486        throw new ObjectDisposedException("TarArchive");
 487      }
 488
 0489      while (true) {
 0490        TarEntry entry = tarIn.GetNextEntry();
 491
 0492         if (entry == null) {
 493          break;
 494        }
 495
 0496         if (entry.TarHeader.TypeFlag == TarHeader.LF_LINK || entry.TarHeader.TypeFlag == TarHeader.LF_SYMLINK)
 497          continue;
 498
 0499        ExtractEntry(destinationDirectory, entry);
 500      }
 0501    }
 502
 503    /// <summary>
 504    /// Extract an entry from the archive. This method assumes that the
 505    /// tarIn stream has been properly set with a call to GetNextEntry().
 506    /// </summary>
 507    /// <param name="destDir">
 508    /// The destination directory into which to extract.
 509    /// </param>
 510    /// <param name="entry">
 511    /// The TarEntry returned by tarIn.GetNextEntry().
 512    /// </param>
 513    void ExtractEntry(string destDir, TarEntry entry)
 514    {
 0515      OnProgressMessageEvent(entry, null);
 516
 0517      string name = entry.Name;
 518
 0519       if (Path.IsPathRooted(name)) {
 520        // NOTE:
 521        // for UNC names...  \\machine\share\zoom\beet.txt gives \zoom\beet.txt
 0522        name = name.Substring(Path.GetPathRoot(name).Length);
 523      }
 524
 0525      name = name.Replace('/', Path.DirectorySeparatorChar);
 526
 0527      string destFile = Path.Combine(destDir, name);
 528
 0529       if (entry.IsDirectory) {
 0530        EnsureDirectoryExists(destFile);
 0531      } else {
 0532        string parentDirectory = Path.GetDirectoryName(destFile);
 0533        EnsureDirectoryExists(parentDirectory);
 534
 0535        bool process = true;
 0536        var fileInfo = new FileInfo(destFile);
 0537         if (fileInfo.Exists) {
 0538           if (keepOldFiles) {
 0539            OnProgressMessageEvent(entry, "Destination file already exists");
 0540            process = false;
 0541           } else if ((fileInfo.Attributes & FileAttributes.ReadOnly) != 0) {
 0542            OnProgressMessageEvent(entry, "Destination file already exists, and is read-only");
 0543            process = false;
 544          }
 545        }
 546
 0547         if (process) {
 0548          bool asciiTrans = false;
 549
 0550          Stream outputStream = File.Create(destFile);
 0551           if (this.asciiTranslate) {
 0552            asciiTrans = !IsBinary(destFile);
 553          }
 554
 0555          StreamWriter outw = null;
 0556           if (asciiTrans) {
 0557            outw = new StreamWriter(outputStream);
 558          }
 559
 0560          byte[] rdbuf = new byte[32 * 1024];
 561
 0562          while (true) {
 0563            int numRead = tarIn.Read(rdbuf, 0, rdbuf.Length);
 564
 0565             if (numRead <= 0) {
 566              break;
 567            }
 568
 0569             if (asciiTrans) {
 0570               for (int off = 0, b = 0; b < numRead; ++b) {
 0571                 if (rdbuf[b] == 10) {
 0572                  string s = Encoding.ASCII.GetString(rdbuf, off, (b - off));
 0573                  outw.WriteLine(s);
 0574                  off = b + 1;
 575                }
 576              }
 0577            } else {
 0578              outputStream.Write(rdbuf, 0, numRead);
 579            }
 580          }
 581
 0582           if (asciiTrans) {
 0583            outw.Close();
 0584          } else {
 0585            outputStream.Close();
 586          }
 587        }
 588      }
 0589    }
 590
 591    /// <summary>
 592    /// Write an entry to the archive. This method will call the putNextEntry
 593    /// and then write the contents of the entry, and finally call closeEntry()
 594    /// for entries that are files. For directories, it will call putNextEntry(),
 595    /// and then, if the recurse flag is true, process each entry that is a
 596    /// child of the directory.
 597    /// </summary>
 598    /// <param name="sourceEntry">
 599    /// The TarEntry representing the entry to write to the archive.
 600    /// </param>
 601    /// <param name="recurse">
 602    /// If true, process the children of directory entries.
 603    /// </param>
 604    public void WriteEntry(TarEntry sourceEntry, bool recurse)
 605    {
 0606       if (sourceEntry == null) {
 0607        throw new ArgumentNullException(nameof(sourceEntry));
 608      }
 609
 0610       if (isDisposed) {
 0611        throw new ObjectDisposedException("TarArchive");
 612      }
 613
 614      try {
 0615         if (recurse) {
 0616          TarHeader.SetValueDefaults(sourceEntry.UserId, sourceEntry.UserName,
 0617                         sourceEntry.GroupId, sourceEntry.GroupName);
 618        }
 0619        WriteEntryCore(sourceEntry, recurse);
 0620      } finally {
 0621         if (recurse) {
 0622          TarHeader.RestoreSetValues();
 623        }
 0624      }
 0625    }
 626
 627    /// <summary>
 628    /// Write an entry to the archive. This method will call the putNextEntry
 629    /// and then write the contents of the entry, and finally call closeEntry()
 630    /// for entries that are files. For directories, it will call putNextEntry(),
 631    /// and then, if the recurse flag is true, process each entry that is a
 632    /// child of the directory.
 633    /// </summary>
 634    /// <param name="sourceEntry">
 635    /// The TarEntry representing the entry to write to the archive.
 636    /// </param>
 637    /// <param name="recurse">
 638    /// If true, process the children of directory entries.
 639    /// </param>
 640    void WriteEntryCore(TarEntry sourceEntry, bool recurse)
 641    {
 0642      string tempFileName = null;
 0643      string entryFilename = sourceEntry.File;
 644
 0645      var entry = (TarEntry)sourceEntry.Clone();
 646
 0647       if (applyUserInfoOverrides) {
 0648        entry.GroupId = groupId;
 0649        entry.GroupName = groupName;
 0650        entry.UserId = userId;
 0651        entry.UserName = userName;
 652      }
 653
 0654      OnProgressMessageEvent(entry, null);
 655
 0656       if (asciiTranslate && !entry.IsDirectory) {
 657
 0658         if (!IsBinary(entryFilename)) {
 0659          tempFileName = Path.GetTempFileName();
 660
 0661          using (StreamReader inStream = File.OpenText(entryFilename)) {
 0662            using (Stream outStream = File.Create(tempFileName)) {
 663
 0664              while (true) {
 0665                string line = inStream.ReadLine();
 0666                 if (line == null) {
 667                  break;
 668                }
 0669                byte[] data = Encoding.ASCII.GetBytes(line);
 0670                outStream.Write(data, 0, data.Length);
 0671                outStream.WriteByte((byte)'\n');
 672              }
 673
 0674              outStream.Flush();
 0675            }
 676          }
 677
 0678          entry.Size = new FileInfo(tempFileName).Length;
 0679          entryFilename = tempFileName;
 680        }
 681      }
 682
 0683      string newName = null;
 684
 0685       if (rootPath != null) {
 0686         if (entry.Name.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase)) {
 0687          newName = entry.Name.Substring(rootPath.Length + 1);
 688        }
 689      }
 690
 0691       if (pathPrefix != null) {
 0692        newName = (newName == null) ? pathPrefix + "/" + entry.Name : pathPrefix + "/" + newName;
 693      }
 694
 0695       if (newName != null) {
 0696        entry.Name = newName;
 697      }
 698
 0699      tarOut.PutNextEntry(entry);
 700
 0701       if (entry.IsDirectory) {
 0702         if (recurse) {
 0703          TarEntry[] list = entry.GetDirectoryEntries();
 0704           for (int i = 0; i < list.Length; ++i) {
 0705            WriteEntryCore(list[i], recurse);
 706          }
 707        }
 0708      } else {
 0709        using (Stream inputStream = File.OpenRead(entryFilename)) {
 0710          byte[] localBuffer = new byte[32 * 1024];
 0711          while (true) {
 0712            int numRead = inputStream.Read(localBuffer, 0, localBuffer.Length);
 713
 0714             if (numRead <= 0) {
 0715              break;
 716            }
 717
 0718            tarOut.Write(localBuffer, 0, numRead);
 719          }
 720        }
 721
 0722         if (!string.IsNullOrEmpty(tempFileName)) {
 0723          File.Delete(tempFileName);
 724        }
 725
 0726        tarOut.CloseEntry();
 727      }
 0728    }
 729
 730    /// <summary>
 731    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
 732    /// </summary>
 733    public void Dispose()
 734    {
 2735      Dispose(true);
 2736      GC.SuppressFinalize(this);
 2737    }
 738
 739    /// <summary>
 740    /// Releases the unmanaged resources used by the FileStream and optionally releases the managed resources.
 741    /// </summary>
 742    /// <param name="disposing">true to release both managed and unmanaged resources;
 743    /// false to release only unmanaged resources.</param>
 744    protected virtual void Dispose(bool disposing)
 745    {
 2746       if (!isDisposed) {
 2747        isDisposed = true;
 2748         if (disposing) {
 2749           if (tarOut != null) {
 1750            tarOut.Flush();
 1751            tarOut.Close();
 752          }
 753
 2754           if (tarIn != null) {
 1755            tarIn.Close();
 756          }
 757        }
 758      }
 2759    }
 760
 761    /// <summary>
 762    /// Closes the archive and releases any associated resources.
 763    /// </summary>
 764    public virtual void Close()
 765    {
 0766      Dispose(true);
 0767    }
 768
 769    /// <summary>
 770    /// Ensures that resources are freed and other cleanup operations are performed
 771    /// when the garbage collector reclaims the <see cref="TarArchive"/>.
 772    /// </summary>
 773    ~TarArchive()
 774    {
 0775      Dispose(false);
 0776    }
 777
 778    static void EnsureDirectoryExists(string directoryName)
 779    {
 0780       if (!Directory.Exists(directoryName)) {
 781        try {
 0782          Directory.CreateDirectory(directoryName);
 0783        } catch (Exception e) {
 0784          throw new TarException("Exception creating directory '" + directoryName + "', " + e.Message, e);
 785        }
 786      }
 0787    }
 788
 789    // TODO: TarArchive - Is there a better way to test for a text file?
 790    // It no longer reads entire files into memory but is still a weak test!
 791    // This assumes that byte values 0-7, 14-31 or 255 are binary
 792    // and that all non text files contain one of these values
 793    static bool IsBinary(string filename)
 794    {
 0795      using (FileStream fs = File.OpenRead(filename)) {
 0796        int sampleSize = Math.Min(4096, (int)fs.Length);
 0797        byte[] content = new byte[sampleSize];
 798
 0799        int bytesRead = fs.Read(content, 0, sampleSize);
 800
 0801         for (int i = 0; i < bytesRead; ++i) {
 0802          byte b = content[i];
 0803           if ((b < 8) || ((b > 13) && (b < 32)) || (b == 255)) {
 0804            return true;
 805          }
 806        }
 0807      }
 0808      return false;
 0809    }
 810
 811    #region Instance Fields
 812    bool keepOldFiles;
 813    bool asciiTranslate;
 814
 815    int userId;
 2816    string userName = string.Empty;
 817    int groupId;
 2818    string groupName = string.Empty;
 819
 820    string rootPath;
 821    string pathPrefix;
 822
 823    bool applyUserInfoOverrides;
 824
 825    TarInputStream tarIn;
 826    TarOutputStream tarOut;
 827    bool isDisposed;
 828    #endregion
 829  }
 830}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_TarBuffer.htm b/docs/opencover/ICSharpCode.SharpZipLib_TarBuffer.htm new file mode 100644 index 000000000..dc727f8d1 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_TarBuffer.htm @@ -0,0 +1,612 @@ + + + + +ICSharpCode.SharpZipLib.Tar.TarBuffer - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Tar.TarBuffer
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarBuffer.cs
Covered lines:96
Uncovered lines:50
Coverable lines:146
Total lines:551
Line coverage:65.7%
Branch coverage:50%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
GetRecordSize()100
GetBlockFactor()100
.ctor()1100100
CreateInputTarBuffer(...)200
CreateInputTarBuffer(...)377.7860
CreateOutputTarBuffer(...)200
CreateOutputTarBuffer(...)377.7860
Initialize(...)2100100
IsEOFBlock(...)500
IsEndOfArchiveBlock(...)58077.78
SkipBlock()400
ReadBlock()477.7857.14
ReadRecord()491.6771.43
GetCurrentBlockNum()100
GetCurrentRecordNum()100
WriteBlock(...)566.6766.67
WriteBlock(...)764.2961.54
WriteRecord()285.7166.67
WriteFinalRecord()387.560
Close()510088.89
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarBuffer.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Tar
 5{
 6  /// <summary>
 7  /// The TarBuffer class implements the tar archive concept
 8  /// of a buffered input stream. This concept goes back to the
 9  /// days of blocked tape drives and special io devices. In the
 10  /// C# universe, the only real function that this class
 11  /// performs is to ensure that files have the correct "record"
 12  /// size, or other tars will complain.
 13  /// <p>
 14  /// You should never have a need to access this class directly.
 15  /// TarBuffers are created by Tar IO Streams.
 16  /// </p>
 17  /// </summary>
 18  public class TarBuffer
 19  {
 20
 21    /* A quote from GNU tar man file on blocking and records
 22       A `tar' archive file contains a series of blocks.  Each block
 23    contains `BLOCKSIZE' bytes.  Although this format may be thought of as
 24    being on magnetic tape, other media are often used.
 25
 26       Each file archived is represented by a header block which describes
 27    the file, followed by zero or more blocks which give the contents of
 28    the file.  At the end of the archive file there may be a block filled
 29    with binary zeros as an end-of-file marker.  A reasonable system should
 30    write a block of zeros at the end, but must not assume that such a
 31    block exists when reading an archive.
 32
 33       The blocks may be "blocked" for physical I/O operations.  Each
 34    record of N blocks is written with a single 'write ()'
 35    operation.  On magnetic tapes, the result of such a write is a single
 36    record.  When writing an archive, the last record of blocks should be
 37    written at the full size, with blocks after the zero block containing
 38    all zeros.  When reading an archive, a reasonable system should
 39    properly handle an archive whose last record is shorter than the rest,
 40    or which contains garbage records after a zero block.
 41    */
 42
 43    #region Constants
 44    /// <summary>
 45    /// The size of a block in a tar archive in bytes.
 46    /// </summary>
 47    /// <remarks>This is 512 bytes.</remarks>
 48    public const int BlockSize = 512;
 49
 50    /// <summary>
 51    /// The number of blocks in a default record.
 52    /// </summary>
 53    /// <remarks>
 54    /// The default value is 20 blocks per record.
 55    /// </remarks>
 56    public const int DefaultBlockFactor = 20;
 57
 58    /// <summary>
 59    /// The size in bytes of a default record.
 60    /// </summary>
 61    /// <remarks>
 62    /// The default size is 10KB.
 63    /// </remarks>
 64    public const int DefaultRecordSize = BlockSize * DefaultBlockFactor;
 65    #endregion
 66
 67    /// <summary>
 68    /// Get the record size for this buffer
 69    /// </summary>
 70    /// <value>The record size in bytes.
 71    /// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></value>
 72    public int RecordSize {
 73      get {
 36074        return recordSize;
 75      }
 76    }
 77
 78    /// <summary>
 79    /// Get the TAR Buffer's record size.
 80    /// </summary>
 81    /// <returns>The record size in bytes.
 82    /// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></returns>
 83    [Obsolete("Use RecordSize property instead")]
 84    public int GetRecordSize()
 85    {
 086      return recordSize;
 87    }
 88
 89    /// <summary>
 90    /// Get the Blocking factor for the buffer
 91    /// </summary>
 92    /// <value>This is the number of blocks in each record.</value>
 93    public int BlockFactor {
 94      get {
 419895        return blockFactor;
 96      }
 97    }
 98
 99    /// <summary>
 100    /// Get the TAR Buffer's block factor
 101    /// </summary>
 102    /// <returns>The block factor; the number of blocks per record.</returns>
 103    [Obsolete("Use BlockFactor property instead")]
 104    public int GetBlockFactor()
 105    {
 0106      return blockFactor;
 107    }
 108
 109    /// <summary>
 110    /// Construct a default TarBuffer
 111    /// </summary>
 78112    protected TarBuffer()
 113    {
 78114    }
 115
 116    /// <summary>
 117    /// Create TarBuffer for reading with default BlockFactor
 118    /// </summary>
 119    /// <param name="inputStream">Stream to buffer</param>
 120    /// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>
 121    public static TarBuffer CreateInputTarBuffer(Stream inputStream)
 122    {
 0123       if (inputStream == null) {
 0124        throw new ArgumentNullException(nameof(inputStream));
 125      }
 126
 0127      return CreateInputTarBuffer(inputStream, DefaultBlockFactor);
 128    }
 129
 130    /// <summary>
 131    /// Construct TarBuffer for reading inputStream setting BlockFactor
 132    /// </summary>
 133    /// <param name="inputStream">Stream to buffer</param>
 134    /// <param name="blockFactor">Blocking factor to apply</param>
 135    /// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>
 136    public static TarBuffer CreateInputTarBuffer(Stream inputStream, int blockFactor)
 137    {
 5138       if (inputStream == null) {
 0139        throw new ArgumentNullException(nameof(inputStream));
 140      }
 141
 5142       if (blockFactor <= 0) {
 0143        throw new ArgumentOutOfRangeException(nameof(blockFactor), "Factor cannot be negative");
 144      }
 145
 5146      var tarBuffer = new TarBuffer();
 5147      tarBuffer.inputStream = inputStream;
 5148      tarBuffer.outputStream = null;
 5149      tarBuffer.Initialize(blockFactor);
 150
 5151      return tarBuffer;
 152    }
 153
 154    /// <summary>
 155    /// Construct TarBuffer for writing with default BlockFactor
 156    /// </summary>
 157    /// <param name="outputStream">output stream for buffer</param>
 158    /// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>
 159    public static TarBuffer CreateOutputTarBuffer(Stream outputStream)
 160    {
 0161       if (outputStream == null) {
 0162        throw new ArgumentNullException(nameof(outputStream));
 163      }
 164
 0165      return CreateOutputTarBuffer(outputStream, DefaultBlockFactor);
 166    }
 167
 168    /// <summary>
 169    /// Construct TarBuffer for writing Tar output to streams.
 170    /// </summary>
 171    /// <param name="outputStream">Output stream to write to.</param>
 172    /// <param name="blockFactor">Blocking factor to apply</param>
 173    /// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>
 174    public static TarBuffer CreateOutputTarBuffer(Stream outputStream, int blockFactor)
 175    {
 73176       if (outputStream == null) {
 0177        throw new ArgumentNullException(nameof(outputStream));
 178      }
 179
 73180       if (blockFactor <= 0) {
 0181        throw new ArgumentOutOfRangeException(nameof(blockFactor), "Factor cannot be negative");
 182      }
 183
 73184      var tarBuffer = new TarBuffer();
 73185      tarBuffer.inputStream = null;
 73186      tarBuffer.outputStream = outputStream;
 73187      tarBuffer.Initialize(blockFactor);
 188
 73189      return tarBuffer;
 190    }
 191
 192    /// <summary>
 193    /// Initialization common to all constructors.
 194    /// </summary>
 195    void Initialize(int archiveBlockFactor)
 196    {
 78197      blockFactor = archiveBlockFactor;
 78198      recordSize = archiveBlockFactor * BlockSize;
 78199      recordBuffer = new byte[RecordSize];
 200
 78201       if (inputStream != null) {
 5202        currentRecordIndex = -1;
 5203        currentBlockIndex = BlockFactor;
 5204      } else {
 73205        currentRecordIndex = 0;
 73206        currentBlockIndex = 0;
 207      }
 73208    }
 209
 210    /// <summary>
 211    /// Determine if an archive block indicates End of Archive. End of
 212    /// archive is indicated by a block that consists entirely of null bytes.
 213    /// All remaining blocks for the record should also be null's
 214    /// However some older tars only do a couple of null blocks (Old GNU tar for one)
 215    /// and also partial records
 216    /// </summary>
 217    /// <param name = "block">The data block to check.</param>
 218    /// <returns>Returns true if the block is an EOF block; false otherwise.</returns>
 219    [Obsolete("Use IsEndOfArchiveBlock instead")]
 220    public bool IsEOFBlock(byte[] block)
 221    {
 0222       if (block == null) {
 0223        throw new ArgumentNullException(nameof(block));
 224      }
 225
 0226       if (block.Length != BlockSize) {
 0227        throw new ArgumentException("block length is invalid");
 228      }
 229
 0230       for (int i = 0; i < BlockSize; ++i) {
 0231         if (block[i] != 0) {
 0232          return false;
 233        }
 234      }
 235
 0236      return true;
 237    }
 238
 239
 240    /// <summary>
 241    /// Determine if an archive block indicates the End of an Archive has been reached.
 242    /// End of archive is indicated by a block that consists entirely of null bytes.
 243    /// All remaining blocks for the record should also be null's
 244    /// However some older tars only do a couple of null blocks (Old GNU tar for one)
 245    /// and also partial records
 246    /// </summary>
 247    /// <param name = "block">The data block to check.</param>
 248    /// <returns>Returns true if the block is an EOF block; false otherwise.</returns>
 249    public static bool IsEndOfArchiveBlock(byte[] block)
 250    {
 3251       if (block == null) {
 0252        throw new ArgumentNullException(nameof(block));
 253      }
 254
 3255       if (block.Length != BlockSize) {
 0256        throw new ArgumentException("block length is invalid");
 257      }
 258
 1030259       for (int i = 0; i < BlockSize; ++i) {
 514260         if (block[i] != 0) {
 2261          return false;
 262        }
 263      }
 264
 1265      return true;
 266    }
 267
 268    /// <summary>
 269    /// Skip over a block on the input stream.
 270    /// </summary>
 271    public void SkipBlock()
 272    {
 0273       if (inputStream == null) {
 0274        throw new TarException("no input stream defined");
 275      }
 276
 0277       if (currentBlockIndex >= BlockFactor) {
 0278         if (!ReadRecord()) {
 0279          throw new TarException("Failed to read a record");
 280        }
 281      }
 282
 0283      currentBlockIndex++;
 0284    }
 285
 286    /// <summary>
 287    /// Read a block from the input stream.
 288    /// </summary>
 289    /// <returns>
 290    /// The block of data read.
 291    /// </returns>
 292    public byte[] ReadBlock()
 293    {
 3294       if (inputStream == null) {
 0295        throw new TarException("TarBuffer.ReadBlock - no input stream defined");
 296      }
 297
 3298       if (currentBlockIndex >= BlockFactor) {
 3299         if (!ReadRecord()) {
 0300          throw new TarException("Failed to read a record");
 301        }
 302      }
 303
 3304      byte[] result = new byte[BlockSize];
 305
 3306      Array.Copy(recordBuffer, (currentBlockIndex * BlockSize), result, 0, BlockSize);
 3307      currentBlockIndex++;
 3308      return result;
 309    }
 310
 311    /// <summary>
 312    /// Read a record from data stream.
 313    /// </summary>
 314    /// <returns>
 315    /// false if End-Of-File, else true.
 316    /// </returns>
 317    bool ReadRecord()
 318    {
 3319       if (inputStream == null) {
 0320        throw new TarException("no input stream stream defined");
 321      }
 322
 3323      currentBlockIndex = 0;
 324
 3325      int offset = 0;
 3326      int bytesNeeded = RecordSize;
 327
 6328       while (bytesNeeded > 0) {
 3329        long numBytes = inputStream.Read(recordBuffer, offset, bytesNeeded);
 330
 331        //
 332        // NOTE
 333        // We have found EOF, and the record is not full!
 334        //
 335        // This is a broken archive. It does not follow the standard
 336        // blocking algorithm. However, because we are generous, and
 337        // it requires little effort, we will simply ignore the error
 338        // and continue as if the entire record were read. This does
 339        // not appear to break anything upstream. We used to return
 340        // false in this case.
 341        //
 342        // Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
 343        //
 3344         if (numBytes <= 0) {
 345          break;
 346        }
 347
 3348        offset += (int)numBytes;
 3349        bytesNeeded -= (int)numBytes;
 350      }
 351
 3352      currentRecordIndex++;
 3353      return true;
 354    }
 355
 356    /// <summary>
 357    /// Get the current block number, within the current record, zero based.
 358    /// </summary>
 359    /// <remarks>Block numbers are zero based values</remarks>
 360    /// <seealso cref="RecordSize"/>
 361    public int CurrentBlock {
 0362      get { return currentBlockIndex; }
 363    }
 364
 365    /// <summary>
 366    /// Get/set flag indicating ownership of the underlying stream.
 367    /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
 368    /// </summary>
 369    public bool IsStreamOwner {
 0370      get { return isStreamOwner_; }
 4371      set { isStreamOwner_ = value; }
 372    }
 373
 374    /// <summary>
 375    /// Get the current block number, within the current record, zero based.
 376    /// </summary>
 377    /// <returns>
 378    /// The current zero based block number.
 379    /// </returns>
 380    /// <remarks>
 381    /// The absolute block number = (<see cref="GetCurrentRecordNum">record number</see> * <see cref="BlockFactor">block
 382    /// </remarks>
 383    [Obsolete("Use CurrentBlock property instead")]
 384    public int GetCurrentBlockNum()
 385    {
 0386      return currentBlockIndex;
 387    }
 388
 389    /// <summary>
 390    /// Get the current record number.
 391    /// </summary>
 392    /// <returns>
 393    /// The current zero based record number.
 394    /// </returns>
 395    public int CurrentRecord {
 0396      get { return currentRecordIndex; }
 397    }
 398
 399    /// <summary>
 400    /// Get the current record number.
 401    /// </summary>
 402    /// <returns>
 403    /// The current zero based record number.
 404    /// </returns>
 405    [Obsolete("Use CurrentRecord property instead")]
 406    public int GetCurrentRecordNum()
 407    {
 0408      return currentRecordIndex;
 409    }
 410
 411    /// <summary>
 412    /// Write a block of data to the archive.
 413    /// </summary>
 414    /// <param name="block">
 415    /// The data to write to the archive.
 416    /// </param>
 417    public void WriteBlock(byte[] block)
 418    {
 148419       if (block == null) {
 0420        throw new ArgumentNullException(nameof(block));
 421      }
 422
 148423       if (outputStream == null) {
 0424        throw new TarException("TarBuffer.WriteBlock - no output stream defined");
 425      }
 426
 148427       if (block.Length != BlockSize) {
 0428        string errorText = string.Format("TarBuffer.WriteBlock - block to write has length '{0}' which is not the block 
 0429          block.Length, BlockSize);
 0430        throw new TarException(errorText);
 431      }
 432
 148433       if (currentBlockIndex >= BlockFactor) {
 4434        WriteRecord();
 435      }
 436
 148437      Array.Copy(block, 0, recordBuffer, (currentBlockIndex * BlockSize), BlockSize);
 148438      currentBlockIndex++;
 148439    }
 440
 441    /// <summary>
 442    /// Write an archive record to the archive, where the record may be
 443    /// inside of a larger array buffer. The buffer must be "offset plus
 444    /// record size" long.
 445    /// </summary>
 446    /// <param name="buffer">
 447    /// The buffer containing the record data to write.
 448    /// </param>
 449    /// <param name="offset">
 450    /// The offset of the record data within buffer.
 451    /// </param>
 452    public void WriteBlock(byte[] buffer, int offset)
 453    {
 4042454       if (buffer == null) {
 0455        throw new ArgumentNullException(nameof(buffer));
 456      }
 457
 4042458       if (outputStream == null) {
 0459        throw new TarException("TarBuffer.WriteBlock - no output stream stream defined");
 460      }
 461
 4042462       if ((offset < 0) || (offset >= buffer.Length)) {
 0463        throw new ArgumentOutOfRangeException(nameof(offset));
 464      }
 465
 4042466       if ((offset + BlockSize) > buffer.Length) {
 0467        string errorText = string.Format("TarBuffer.WriteBlock - record has length '{0}' with offset '{1}' which is less
 0468          buffer.Length, offset, recordSize);
 0469        throw new TarException(errorText);
 470      }
 471
 4042472       if (currentBlockIndex >= BlockFactor) {
 128473        WriteRecord();
 474      }
 475
 4042476      Array.Copy(buffer, offset, recordBuffer, (currentBlockIndex * BlockSize), BlockSize);
 477
 4042478      currentBlockIndex++;
 4042479    }
 480
 481    /// <summary>
 482    /// Write a TarBuffer record to the archive.
 483    /// </summary>
 484    void WriteRecord()
 485    {
 205486       if (outputStream == null) {
 0487        throw new TarException("TarBuffer.WriteRecord no output stream defined");
 488      }
 489
 205490      outputStream.Write(recordBuffer, 0, RecordSize);
 205491      outputStream.Flush();
 492
 205493      currentBlockIndex = 0;
 205494      currentRecordIndex++;
 205495    }
 496
 497    /// <summary>
 498    /// WriteFinalRecord writes the current record buffer to output any unwritten data is present.
 499    /// </summary>
 500    /// <remarks>Any trailing bytes are set to zero which is by definition correct behaviour
 501    /// for the end of a tar stream.</remarks>
 502    void WriteFinalRecord()
 503    {
 73504       if (outputStream == null) {
 0505        throw new TarException("TarBuffer.WriteFinalRecord no output stream defined");
 506      }
 507
 73508       if (currentBlockIndex > 0) {
 73509        int dataBytes = currentBlockIndex * BlockSize;
 73510        Array.Clear(recordBuffer, dataBytes, RecordSize - dataBytes);
 73511        WriteRecord();
 512      }
 513
 73514      outputStream.Flush();
 73515    }
 516
 517    /// <summary>
 518    /// Close the TarBuffer. If this is an output buffer, also flush the
 519    /// current block before closing.
 520    /// </summary>
 521    public void Close()
 522    {
 78523       if (outputStream != null) {
 73524        WriteFinalRecord();
 525
 73526         if (isStreamOwner_) {
 72527          outputStream.Close();
 528        }
 73529        outputStream = null;
 78530       } else if (inputStream != null) {
 5531         if (isStreamOwner_) {
 4532          inputStream.Close();
 533        }
 5534        inputStream = null;
 535      }
 5536    }
 537
 538    #region Instance Fields
 539    Stream inputStream;
 540    Stream outputStream;
 541
 542    byte[] recordBuffer;
 543    int currentBlockIndex;
 544    int currentRecordIndex;
 545
 78546    int recordSize = DefaultRecordSize;
 78547    int blockFactor = DefaultBlockFactor;
 78548    bool isStreamOwner_ = true;
 549    #endregion
 550  }
 551}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_TarEntry.htm b/docs/opencover/ICSharpCode.SharpZipLib_TarEntry.htm new file mode 100644 index 000000000..6c370704b --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_TarEntry.htm @@ -0,0 +1,553 @@ + + + + +ICSharpCode.SharpZipLib.Tar.TarEntry - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Tar.TarEntry
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarEntry.cs
Covered lines:61
Uncovered lines:61
Coverable lines:122
Total lines:496
Line coverage:50%
Branch coverage:21.4%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
.ctor(...)1100100
.ctor(...)28066.67
Clone()1100100
CreateTarEntry(...)1100100
CreateEntryFromFile(...)100
Equals(...)200
GetHashCode()100
IsDescendent(...)200
SetIds(...)100
SetNames(...)100
GetFileTarHeader(...)800
GetDirectoryEntries()400
WriteEntryHeader(...)1100100
AdjustEntryName(...)100
NameTarHeader(...)788.8955.56
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarEntry.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Tar
 5{
 6  /// <summary>
 7  /// This class represents an entry in a Tar archive. It consists
 8  /// of the entry's header, as well as the entry's File. Entries
 9  /// can be instantiated in one of three ways, depending on how
 10  /// they are to be used.
 11  /// <p>
 12  /// TarEntries that are created from the header bytes read from
 13  /// an archive are instantiated with the TarEntry( byte[] )
 14  /// constructor. These entries will be used when extracting from
 15  /// or listing the contents of an archive. These entries have their
 16  /// header filled in using the header bytes. They also set the File
 17  /// to null, since they reference an archive entry not a file.</p>
 18  /// <p>
 19  /// TarEntries that are created from files that are to be written
 20  /// into an archive are instantiated with the CreateEntryFromFile(string)
 21  /// pseudo constructor. These entries have their header filled in using
 22  /// the File's information. They also keep a reference to the File
 23  /// for convenience when writing entries.</p>
 24  /// <p>
 25  /// Finally, TarEntries can be constructed from nothing but a name.
 26  /// This allows the programmer to construct the entry by hand, for
 27  /// instance when only an InputStream is available for writing to
 28  /// the archive, and the header information is constructed from
 29  /// other information. In this case the header fields are set to
 30  /// defaults and the File is set to null.</p>
 31  /// <see cref="TarHeader"/>
 32  /// </summary>
 33  public class TarEntry : ICloneable
 34  {
 35    #region Constructors
 36    /// <summary>
 37    /// Initialise a default instance of <see cref="TarEntry"/>.
 38    /// </summary>
 7939    private TarEntry()
 40    {
 7941      header = new TarHeader();
 7942    }
 43
 44    /// <summary>
 45    /// Construct an entry from an archive's header bytes. File is set
 46    /// to null.
 47    /// </summary>
 48    /// <param name = "headerBuffer">
 49    /// The header bytes from a tar archive entry.
 50    /// </param>
 151    public TarEntry(byte[] headerBuffer)
 52    {
 153      header = new TarHeader();
 154      header.ParseBuffer(headerBuffer);
 155    }
 56
 57    /// <summary>
 58    /// Construct a TarEntry using the <paramref name="header">header</paramref> provided
 59    /// </summary>
 60    /// <param name="header">Header details for entry</param>
 161    public TarEntry(TarHeader header)
 62    {
 163       if (header == null) {
 064        throw new ArgumentNullException(nameof(header));
 65      }
 66
 167      this.header = (TarHeader)header.Clone();
 168    }
 69    #endregion
 70
 71    #region ICloneable Members
 72    /// <summary>
 73    /// Clone this tar entry.
 74    /// </summary>
 75    /// <returns>Returns a clone of this entry.</returns>
 76    public object Clone()
 77    {
 178      var entry = new TarEntry();
 179      entry.file = file;
 180      entry.header = (TarHeader)header.Clone();
 181      entry.Name = Name;
 182      return entry;
 83    }
 84    #endregion
 85
 86    /// <summary>
 87    /// Construct an entry with only a <paramref name="name">name</paramref>.
 88    /// This allows the programmer to construct the entry's header "by hand".
 89    /// </summary>
 90    /// <param name="name">The name to use for the entry</param>
 91    /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
 92    public static TarEntry CreateTarEntry(string name)
 93    {
 7894      var entry = new TarEntry();
 7895      TarEntry.NameTarHeader(entry.header, name);
 7896      return entry;
 97    }
 98
 99    /// <summary>
 100    /// Construct an entry for a file. File is set to file, and the
 101    /// header is constructed from information from the file.
 102    /// </summary>
 103    /// <param name = "fileName">The file name that the entry represents.</param>
 104    /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
 105    public static TarEntry CreateEntryFromFile(string fileName)
 106    {
 0107      var entry = new TarEntry();
 0108      entry.GetFileTarHeader(entry.header, fileName);
 0109      return entry;
 110    }
 111
 112    /// <summary>
 113    /// Determine if the two entries are equal. Equality is determined
 114    /// by the header names being equal.
 115    /// </summary>
 116    /// <param name="obj">The <see cref="Object"/> to compare with the current Object.</param>
 117    /// <returns>
 118    /// True if the entries are equal; false if not.
 119    /// </returns>
 120    public override bool Equals(object obj)
 121    {
 0122      var localEntry = obj as TarEntry;
 123
 0124       if (localEntry != null) {
 0125        return Name.Equals(localEntry.Name);
 126      }
 0127      return false;
 128    }
 129
 130    /// <summary>
 131    /// Derive a Hash value for the current <see cref="Object"/>
 132    /// </summary>
 133    /// <returns>A Hash code for the current <see cref="Object"/></returns>
 134    public override int GetHashCode()
 135    {
 0136      return Name.GetHashCode();
 137    }
 138
 139    /// <summary>
 140    /// Determine if the given entry is a descendant of this entry.
 141    /// Descendancy is determined by the name of the descendant
 142    /// starting with this entry's name.
 143    /// </summary>
 144    /// <param name = "toTest">
 145    /// Entry to be checked as a descendent of this.
 146    /// </param>
 147    /// <returns>
 148    /// True if entry is a descendant of this.
 149    /// </returns>
 150    public bool IsDescendent(TarEntry toTest)
 151    {
 0152       if (toTest == null) {
 0153        throw new ArgumentNullException(nameof(toTest));
 154      }
 155
 0156      return toTest.Name.StartsWith(Name, StringComparison.Ordinal);
 157    }
 158
 159    /// <summary>
 160    /// Get this entry's header.
 161    /// </summary>
 162    /// <returns>
 163    /// This entry's TarHeader.
 164    /// </returns>
 165    public TarHeader TarHeader {
 166      get {
 78167        return header;
 168      }
 169    }
 170
 171    /// <summary>
 172    /// Get/Set this entry's name.
 173    /// </summary>
 174    public string Name {
 175      get {
 73176        return header.Name;
 177      }
 178      set {
 2179        header.Name = value;
 1180      }
 181    }
 182
 183    /// <summary>
 184    /// Get/set this entry's user id.
 185    /// </summary>
 186    public int UserId {
 187      get {
 0188        return header.UserId;
 189      }
 190      set {
 0191        header.UserId = value;
 0192      }
 193    }
 194
 195    /// <summary>
 196    /// Get/set this entry's group id.
 197    /// </summary>
 198    public int GroupId {
 199      get {
 2200        return header.GroupId;
 201      }
 202      set {
 1203        header.GroupId = value;
 1204      }
 205    }
 206
 207    /// <summary>
 208    /// Get/set this entry's user name.
 209    /// </summary>
 210    public string UserName {
 211      get {
 2212        return header.UserName;
 213      }
 214      set {
 2215        header.UserName = value;
 2216      }
 217    }
 218
 219    /// <summary>
 220    /// Get/set this entry's group name.
 221    /// </summary>
 222    public string GroupName {
 223      get {
 3224        return header.GroupName;
 225      }
 226      set {
 2227        header.GroupName = value;
 2228      }
 229    }
 230
 231    /// <summary>
 232    /// Convenience method to set this entry's group and user ids.
 233    /// </summary>
 234    /// <param name="userId">
 235    /// This entry's new user id.
 236    /// </param>
 237    /// <param name="groupId">
 238    /// This entry's new group id.
 239    /// </param>
 240    public void SetIds(int userId, int groupId)
 241    {
 0242      UserId = userId;
 0243      GroupId = groupId;
 0244    }
 245
 246    /// <summary>
 247    /// Convenience method to set this entry's group and user names.
 248    /// </summary>
 249    /// <param name="userName">
 250    /// This entry's new user name.
 251    /// </param>
 252    /// <param name="groupName">
 253    /// This entry's new group name.
 254    /// </param>
 255    public void SetNames(string userName, string groupName)
 256    {
 0257      UserName = userName;
 0258      GroupName = groupName;
 0259    }
 260
 261    /// <summary>
 262    /// Get/Set the modification time for this entry
 263    /// </summary>
 264    public DateTime ModTime {
 265      get {
 2266        return header.ModTime;
 267      }
 268      set {
 2269        header.ModTime = value;
 1270      }
 271    }
 272
 273    /// <summary>
 274    /// Get this entry's file.
 275    /// </summary>
 276    /// <returns>
 277    /// This entry's file.
 278    /// </returns>
 279    public string File {
 280      get {
 2281        return file;
 282      }
 283    }
 284
 285    /// <summary>
 286    /// Get/set this entry's recorded file size.
 287    /// </summary>
 288    public long Size {
 289      get {
 73290        return header.Size;
 291      }
 292      set {
 70293        header.Size = value;
 69294      }
 295    }
 296
 297    /// <summary>
 298    /// Return true if this entry represents a directory, false otherwise
 299    /// </summary>
 300    /// <returns>
 301    /// True if this entry is a directory.
 302    /// </returns>
 303    public bool IsDirectory {
 304      get {
 72305         if (file != null) {
 0306          return Directory.Exists(file);
 307        }
 308
 72309         if (header != null) {
 72310           if ((header.TypeFlag == TarHeader.LF_DIR) || Name.EndsWith("/", StringComparison.Ordinal)) {
 0311            return true;
 312          }
 313        }
 72314        return false;
 315      }
 316    }
 317
 318    /// <summary>
 319    /// Fill in a TarHeader with information from a File.
 320    /// </summary>
 321    /// <param name="header">
 322    /// The TarHeader to fill in.
 323    /// </param>
 324    /// <param name="file">
 325    /// The file from which to get the header information.
 326    /// </param>
 327    public void GetFileTarHeader(TarHeader header, string file)
 328    {
 0329       if (header == null) {
 0330        throw new ArgumentNullException(nameof(header));
 331      }
 332
 0333       if (file == null) {
 0334        throw new ArgumentNullException(nameof(file));
 335      }
 336
 0337      this.file = file;
 338
 339      // bugfix from torhovl from #D forum:
 0340      string name = file;
 341
 342      // 23-Jan-2004 GnuTar allows device names in path where the name is not local to the current directory
 0343       if (name.IndexOf(Environment.CurrentDirectory, StringComparison.Ordinal) == 0) {
 0344        name = name.Substring(Environment.CurrentDirectory.Length);
 345      }
 346
 347      /*
 348            if (Path.DirectorySeparatorChar == '\\')
 349            {
 350              // check if the OS is Windows
 351              // Strip off drive letters!
 352              if (name.Length > 2)
 353              {
 354                char ch1 = name[0];
 355                char ch2 = name[1];
 356
 357                if (ch2 == ':' && Char.IsLetter(ch1))
 358                {
 359                  name = name.Substring(2);
 360                }
 361              }
 362            }
 363      */
 364
 0365      name = name.Replace(Path.DirectorySeparatorChar, '/');
 366
 367      // No absolute pathnames
 368      // Windows (and Posix?) paths can start with UNC style "\\NetworkDrive\",
 369      // so we loop on starting /'s.
 0370       while (name.StartsWith("/", StringComparison.Ordinal)) {
 0371        name = name.Substring(1);
 372      }
 373
 0374      header.LinkName = String.Empty;
 0375      header.Name = name;
 376
 0377       if (Directory.Exists(file)) {
 0378        header.Mode = 1003; // Magic number for security access for a UNIX filesystem
 0379        header.TypeFlag = TarHeader.LF_DIR;
 0380         if ((header.Name.Length == 0) || header.Name[header.Name.Length - 1] != '/') {
 0381          header.Name = header.Name + "/";
 382        }
 383
 0384        header.Size = 0;
 0385      } else {
 0386        header.Mode = 33216; // Magic number for security access for a UNIX filesystem
 0387        header.TypeFlag = TarHeader.LF_NORMAL;
 0388        header.Size = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length;
 389      }
 390
 0391      header.ModTime = System.IO.File.GetLastWriteTime(file.Replace('/', Path.DirectorySeparatorChar)).ToUniversalTime()
 0392      header.DevMajor = 0;
 0393      header.DevMinor = 0;
 0394    }
 395
 396    /// <summary>
 397    /// Get entries for all files present in this entries directory.
 398    /// If this entry doesnt represent a directory zero entries are returned.
 399    /// </summary>
 400    /// <returns>
 401    /// An array of TarEntry's for this entry's children.
 402    /// </returns>
 403    public TarEntry[] GetDirectoryEntries()
 404    {
 0405       if ((file == null) || !Directory.Exists(file)) {
 0406        return new TarEntry[0];
 407      }
 408
 0409      string[] list = Directory.GetFileSystemEntries(file);
 0410      TarEntry[] result = new TarEntry[list.Length];
 411
 0412       for (int i = 0; i < list.Length; ++i) {
 0413        result[i] = TarEntry.CreateEntryFromFile(list[i]);
 414      }
 415
 0416      return result;
 417    }
 418
 419    /// <summary>
 420    /// Write an entry's header information to a header buffer.
 421    /// </summary>
 422    /// <param name = "outBuffer">
 423    /// The tar entry header buffer to fill in.
 424    /// </param>
 425    public void WriteEntryHeader(byte[] outBuffer)
 426    {
 70427      header.WriteHeader(outBuffer);
 70428    }
 429
 430    /// <summary>
 431    /// Convenience method that will modify an entry's name directly
 432    /// in place in an entry header buffer byte array.
 433    /// </summary>
 434    /// <param name="buffer">
 435    /// The buffer containing the entry header to modify.
 436    /// </param>
 437    /// <param name="newName">
 438    /// The new name to place into the header buffer.
 439    /// </param>
 440    static public void AdjustEntryName(byte[] buffer, string newName)
 441    {
 0442      TarHeader.GetNameBytes(newName, buffer, 0, TarHeader.NAMELEN);
 0443    }
 444
 445    /// <summary>
 446    /// Fill in a TarHeader given only the entry's name.
 447    /// </summary>
 448    /// <param name="header">
 449    /// The TarHeader to fill in.
 450    /// </param>
 451    /// <param name="name">
 452    /// The tar entry name.
 453    /// </param>
 454    static public void NameTarHeader(TarHeader header, string name)
 455    {
 78456       if (header == null) {
 0457        throw new ArgumentNullException(nameof(header));
 458      }
 459
 78460       if (name == null) {
 0461        throw new ArgumentNullException(nameof(name));
 462      }
 463
 78464      bool isDir = name.EndsWith("/", StringComparison.Ordinal);
 465
 78466      header.Name = name;
 78467       header.Mode = isDir ? 1003 : 33216;
 78468      header.UserId = 0;
 78469      header.GroupId = 0;
 78470      header.Size = 0;
 471
 78472      header.ModTime = DateTime.UtcNow;
 473
 78474       header.TypeFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;
 475
 78476      header.LinkName = String.Empty;
 78477      header.UserName = String.Empty;
 78478      header.GroupName = String.Empty;
 479
 78480      header.DevMajor = 0;
 78481      header.DevMinor = 0;
 78482    }
 483
 484    #region Instance Fields
 485    /// <summary>
 486    /// The name of the file this entry represents or null if the entry is not based on a file.
 487    /// </summary>
 488    string file;
 489
 490    /// <summary>
 491    /// The entry's header information.
 492    /// </summary>
 493    TarHeader header;
 494    #endregion
 495  }
 496}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_TarException.htm b/docs/opencover/ICSharpCode.SharpZipLib_TarException.htm new file mode 100644 index 000000000..36647d078 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_TarException.htm @@ -0,0 +1,92 @@ + + + + +ICSharpCode.SharpZipLib.Tar.TarException - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Tar.TarException
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarException.cs
Covered lines:2
Uncovered lines:6
Coverable lines:8
Total lines:48
Line coverage:25%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor()100
.ctor(...)1100100
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarException.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Runtime.Serialization;
 3
 4namespace ICSharpCode.SharpZipLib.Tar
 5{
 6  /// <summary>
 7  /// TarException represents exceptions specific to Tar classes and code.
 8  /// </summary>
 9  [Serializable]
 10  public class TarException : SharpZipBaseException
 11  {
 12    /// <summary>
 13    /// Deserialization constructor
 14    /// </summary>
 15    /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
 16    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
 17    protected TarException(SerializationInfo info, StreamingContext context)
 018      : base(info, context)
 19    {
 020    }
 21
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="TarException" />.
 24    /// </summary>
 025    public TarException()
 26    {
 027    }
 28
 29    /// <summary>
 30    /// Initialise a new instance of <see cref="TarException" /> with its message string.
 31    /// </summary>
 32    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 33    public TarException(string message)
 134      : base(message)
 35    {
 136    }
 37
 38    /// <summary>
 39    /// Initialise a new instance of <see cref="TarException" />.
 40    /// </summary>
 41    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 42    /// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
 43    public TarException(string message, Exception innerException)
 044      : base(message, innerException)
 45    {
 046    }
 47  }
 48}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_TarHeader.htm b/docs/opencover/ICSharpCode.SharpZipLib_TarHeader.htm new file mode 100644 index 000000000..0b6d2fa9a --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_TarHeader.htm @@ -0,0 +1,1143 @@ + + + + +ICSharpCode.SharpZipLib.Tar.TarHeader - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Tar.TarHeader
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarHeader.cs
Covered lines:209
Uncovered lines:63
Coverable lines:272
Total lines:1077
Line coverage:76.8%
Branch coverage:66.9%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
GetName()100
Clone()1100100
ParseBuffer(...)463.1642.86
WriteHeader(...)689.6672.73
GetHashCode()100
Equals(...)1683.3366.67
SetValueDefaults(...)100
RestoreSetValues()100
ParseBinaryOrOctal(...)32540
ParseOctal(...)893.3373.33
ParseName(...)773.3369.23
GetNameBytes(...)300
GetNameBytes(...)683.3372.73
GetNameBytes(...)300
GetNameBytes(...)36060
GetAsciiBytes(...)577.7877.78
GetOctalBytes(...)693.3390.91
GetBinaryOrOctalBytes(...)322.2240
GetCheckSumOctalBytes(...)1100100
ComputeCheckSum(...)2100100
MakeCheckSum(...)4100100
GetCTime(...)1100100
GetDateTimeFromCTime(...)150100
.cctor()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarHeader.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Text;
 3
 4namespace ICSharpCode.SharpZipLib.Tar
 5{
 6  /// <summary>
 7  /// This class encapsulates the Tar Entry Header used in Tar Archives.
 8  /// The class also holds a number of tar constants, used mostly in headers.
 9  /// </summary>
 10  /// <remarks>
 11  ///    The tar format and its POSIX successor PAX have a long history which makes for compatability
 12  ///    issues when creating and reading files.
 13  ///
 14  ///    This is further complicated by a large number of programs with variations on formats
 15  ///    One common issue is the handling of names longer than 100 characters.
 16  ///    GNU style long names are currently supported.
 17  ///
 18  /// This is the ustar (Posix 1003.1) header.
 19  ///
 20  /// struct header
 21  /// {
 22  ///   char t_name[100];          //   0 Filename
 23  ///   char t_mode[8];            // 100 Permissions
 24  ///   char t_uid[8];             // 108 Numerical User ID
 25  ///   char t_gid[8];             // 116 Numerical Group ID
 26  ///   char t_size[12];           // 124 Filesize
 27  ///   char t_mtime[12];          // 136 st_mtime
 28  ///   char t_chksum[8];          // 148 Checksum
 29  ///   char t_typeflag;           // 156 Type of File
 30  ///   char t_linkname[100];      // 157 Target of Links
 31  ///   char t_magic[6];           // 257 "ustar" or other...
 32  ///   char t_version[2];         // 263 Version fixed to 00
 33  ///   char t_uname[32];          // 265 User Name
 34  ///   char t_gname[32];          // 297 Group Name
 35  ///   char t_devmajor[8];        // 329 Major for devices
 36  ///   char t_devminor[8];        // 337 Minor for devices
 37  ///   char t_prefix[155];        // 345 Prefix for t_name
 38  ///   char t_mfill[12];          // 500 Filler up to 512
 39  /// };
 40  /// </remarks>
 41  public class TarHeader : ICloneable
 42  {
 43    #region Constants
 44    /// <summary>
 45    /// The length of the name field in a header buffer.
 46    /// </summary>
 47    public const int NAMELEN = 100;
 48
 49    /// <summary>
 50    /// The length of the mode field in a header buffer.
 51    /// </summary>
 52    public const int MODELEN = 8;
 53
 54    /// <summary>
 55    /// The length of the user id field in a header buffer.
 56    /// </summary>
 57    public const int UIDLEN = 8;
 58
 59    /// <summary>
 60    /// The length of the group id field in a header buffer.
 61    /// </summary>
 62    public const int GIDLEN = 8;
 63
 64    /// <summary>
 65    /// The length of the checksum field in a header buffer.
 66    /// </summary>
 67    public const int CHKSUMLEN = 8;
 68
 69    /// <summary>
 70    /// Offset of checksum in a header buffer.
 71    /// </summary>
 72    public const int CHKSUMOFS = 148;
 73
 74    /// <summary>
 75    /// The length of the size field in a header buffer.
 76    /// </summary>
 77    public const int SIZELEN = 12;
 78
 79    /// <summary>
 80    /// The length of the magic field in a header buffer.
 81    /// </summary>
 82    public const int MAGICLEN = 6;
 83
 84    /// <summary>
 85    /// The length of the version field in a header buffer.
 86    /// </summary>
 87    public const int VERSIONLEN = 2;
 88
 89    /// <summary>
 90    /// The length of the modification time field in a header buffer.
 91    /// </summary>
 92    public const int MODTIMELEN = 12;
 93
 94    /// <summary>
 95    /// The length of the user name field in a header buffer.
 96    /// </summary>
 97    public const int UNAMELEN = 32;
 98
 99    /// <summary>
 100    /// The length of the group name field in a header buffer.
 101    /// </summary>
 102    public const int GNAMELEN = 32;
 103
 104    /// <summary>
 105    /// The length of the devices field in a header buffer.
 106    /// </summary>
 107    public const int DEVLEN = 8;
 108
 109    /// <summary>
 110    /// The length of the name prefix field in a header buffer.
 111    /// </summary>
 112    public const int PREFIXLEN = 155;
 113
 114    //
 115    // LF_ constants represent the "type" of an entry
 116    //
 117
 118    /// <summary>
 119    ///  The "old way" of indicating a normal file.
 120    /// </summary>
 121    public const byte LF_OLDNORM = 0;
 122
 123    /// <summary>
 124    /// Normal file type.
 125    /// </summary>
 126    public const byte LF_NORMAL = (byte)'0';
 127
 128    /// <summary>
 129    /// Link file type.
 130    /// </summary>
 131    public const byte LF_LINK = (byte)'1';
 132
 133    /// <summary>
 134    /// Symbolic link file type.
 135    /// </summary>
 136    public const byte LF_SYMLINK = (byte)'2';
 137
 138    /// <summary>
 139    /// Character device file type.
 140    /// </summary>
 141    public const byte LF_CHR = (byte)'3';
 142
 143    /// <summary>
 144    /// Block device file type.
 145    /// </summary>
 146    public const byte LF_BLK = (byte)'4';
 147
 148    /// <summary>
 149    /// Directory file type.
 150    /// </summary>
 151    public const byte LF_DIR = (byte)'5';
 152
 153    /// <summary>
 154    /// FIFO (pipe) file type.
 155    /// </summary>
 156    public const byte LF_FIFO = (byte)'6';
 157
 158    /// <summary>
 159    /// Contiguous file type.
 160    /// </summary>
 161    public const byte LF_CONTIG = (byte)'7';
 162
 163    /// <summary>
 164    /// Posix.1 2001 global extended header
 165    /// </summary>
 166    public const byte LF_GHDR = (byte)'g';
 167
 168    /// <summary>
 169    /// Posix.1 2001 extended header
 170    /// </summary>
 171    public const byte LF_XHDR = (byte)'x';
 172
 173    // POSIX allows for upper case ascii type as extensions
 174
 175    /// <summary>
 176    /// Solaris access control list file type
 177    /// </summary>
 178    public const byte LF_ACL = (byte)'A';
 179
 180    /// <summary>
 181    /// GNU dir dump file type
 182    /// This is a dir entry that contains the names of files that were in the
 183    /// dir at the time the dump was made
 184    /// </summary>
 185    public const byte LF_GNU_DUMPDIR = (byte)'D';
 186
 187    /// <summary>
 188    /// Solaris Extended Attribute File
 189    /// </summary>
 190    public const byte LF_EXTATTR = (byte)'E';
 191
 192    /// <summary>
 193    /// Inode (metadata only) no file content
 194    /// </summary>
 195    public const byte LF_META = (byte)'I';
 196
 197    /// <summary>
 198    /// Identifies the next file on the tape as having a long link name
 199    /// </summary>
 200    public const byte LF_GNU_LONGLINK = (byte)'K';
 201
 202    /// <summary>
 203    /// Identifies the next file on the tape as having a long name
 204    /// </summary>
 205    public const byte LF_GNU_LONGNAME = (byte)'L';
 206
 207    /// <summary>
 208    /// Continuation of a file that began on another volume
 209    /// </summary>
 210    public const byte LF_GNU_MULTIVOL = (byte)'M';
 211
 212    /// <summary>
 213    /// For storing filenames that dont fit in the main header (old GNU)
 214    /// </summary>
 215    public const byte LF_GNU_NAMES = (byte)'N';
 216
 217    /// <summary>
 218    /// GNU Sparse file
 219    /// </summary>
 220    public const byte LF_GNU_SPARSE = (byte)'S';
 221
 222    /// <summary>
 223    /// GNU Tape/volume header ignore on extraction
 224    /// </summary>
 225    public const byte LF_GNU_VOLHDR = (byte)'V';
 226
 227    /// <summary>
 228    /// The magic tag representing a POSIX tar archive.  (includes trailing NULL)
 229    /// </summary>
 230    public const string TMAGIC = "ustar ";
 231
 232    /// <summary>
 233    /// The magic tag representing an old GNU tar archive where version is included in magic and overwrites it
 234    /// </summary>
 235    public const string GNU_TMAGIC = "ustar  ";
 236
 237    const long timeConversionFactor = 10000000L;           // 1 tick == 100 nanoseconds
 1238    readonly static DateTime dateTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0);
 239    #endregion
 240
 241    #region Constructors
 242
 243    /// <summary>
 244    /// Initialise a default TarHeader instance
 245    /// </summary>
 84246    public TarHeader()
 247    {
 84248      Magic = TMAGIC;
 84249      Version = " ";
 250
 84251      Name = "";
 84252      LinkName = "";
 253
 84254      UserId = defaultUserId;
 84255      GroupId = defaultGroupId;
 84256      UserName = defaultUser;
 84257      GroupName = defaultGroupName;
 84258      Size = 0;
 84259    }
 260
 261    #endregion
 262
 263    #region Properties
 264    /// <summary>
 265    /// Get/set the name for this tar entry.
 266    /// </summary>
 267    /// <exception cref="ArgumentNullException">Thrown when attempting to set the property to null.</exception>
 268    public string Name {
 214269      get { return name; }
 270      set {
 166271         if (value == null) {
 1272          throw new ArgumentNullException(nameof(value));
 273        }
 165274        name = value;
 165275      }
 276    }
 277
 278    /// <summary>
 279    /// Get the name of this entry.
 280    /// </summary>
 281    /// <returns>The entry's name.</returns>
 282    [Obsolete("Use the Name property instead", true)]
 283    public string GetName()
 284    {
 0285      return name;
 286    }
 287
 288    /// <summary>
 289    /// Get/set the entry's Unix style permission mode.
 290    /// </summary>
 291    public int Mode {
 1292      get { return mode; }
 162293      set { mode = value; }
 294    }
 295
 296
 297    /// <summary>
 298    /// The entry's user id.
 299    /// </summary>
 300    /// <remarks>
 301    /// This is only directly relevant to unix systems.
 302    /// The default is zero.
 303    /// </remarks>
 304    public int UserId {
 125305      get { return userId; }
 334306      set { userId = value; }
 307    }
 308
 309
 310    /// <summary>
 311    /// Get/set the entry's group id.
 312    /// </summary>
 313    /// <remarks>
 314    /// This is only directly relevant to linux/unix systems.
 315    /// The default value is zero.
 316    /// </remarks>
 317    public int GroupId {
 125318      get { return groupId; }
 336319      set { groupId = value; }
 320    }
 321
 322
 323    /// <summary>
 324    /// Get/set the entry's size.
 325    /// </summary>
 326    /// <exception cref="ArgumentOutOfRangeException">Thrown when setting the size to less than zero.</exception>
 327    public long Size {
 195328      get { return size; }
 329      set {
 237330         if (value < 0) {
 1331          throw new ArgumentOutOfRangeException(nameof(value), "Cannot be less than zero");
 332        }
 236333        size = value;
 236334      }
 335    }
 336
 337
 338    /// <summary>
 339    /// Get/set the entry's modification time.
 340    /// </summary>
 341    /// <remarks>
 342    /// The modification time is only accurate to within a second.
 343    /// </remarks>
 344    /// <exception cref="ArgumentOutOfRangeException">Thrown when setting the date time to less than 1/1/1970.</exceptio
 345    public DateTime ModTime {
 121346      get { return modTime; }
 347      set {
 85348         if (value < dateTime1970) {
 1349          throw new ArgumentOutOfRangeException(nameof(value), "ModTime cannot be before Jan 1st 1970");
 350        }
 84351        modTime = new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second);
 84352      }
 353    }
 354
 355
 356    /// <summary>
 357    /// Get the entry's checksum.  This is only valid/updated after writing or reading an entry.
 358    /// </summary>
 359    public int Checksum {
 51360      get { return checksum; }
 361    }
 362
 363
 364    /// <summary>
 365    /// Get value of true if the header checksum is valid, false otherwise.
 366    /// </summary>
 367    public bool IsChecksumValid {
 3368      get { return isChecksumValid; }
 369    }
 370
 371
 372    /// <summary>
 373    /// Get/set the entry's type flag.
 374    /// </summary>
 375    public byte TypeFlag {
 334376      get { return typeFlag; }
 166377      set { typeFlag = value; }
 378    }
 379
 380
 381    /// <summary>
 382    /// The entry's link name.
 383    /// </summary>
 384    /// <exception cref="ArgumentNullException">Thrown when attempting to set LinkName to null.</exception>
 385    public string LinkName {
 120386      get { return linkName; }
 387      set {
 170388         if (value == null) {
 1389          throw new ArgumentNullException(nameof(value));
 390        }
 169391        linkName = value;
 169392      }
 393    }
 394
 395
 396    /// <summary>
 397    /// Get/set the entry's magic tag.
 398    /// </summary>
 399    /// <exception cref="ArgumentNullException">Thrown when attempting to set Magic to null.</exception>
 400    public string Magic {
 116401      get { return magic; }
 402      set {
 90403         if (value == null) {
 1404          throw new ArgumentNullException(nameof(value));
 405        }
 89406        magic = value;
 89407      }
 408    }
 409
 410
 411    /// <summary>
 412    /// The entry's version.
 413    /// </summary>
 414    /// <exception cref="ArgumentNullException">Thrown when attempting to set Version to null.</exception>
 415    public string Version {
 416      get {
 111417        return version;
 418      }
 419
 420      set {
 87421         if (value == null) {
 1422          throw new ArgumentNullException(nameof(value));
 423        }
 86424        version = value;
 86425      }
 426    }
 427
 428
 429    /// <summary>
 430    /// The entry's user name.
 431    /// </summary>
 432    public string UserName {
 111433      get { return userName; }
 434      set {
 166435         if (value != null) {
 81436          userName = value.Substring(0, Math.Min(UNAMELEN, value.Length));
 81437        } else {
 85438          string currentUser = Environment.UserName;
 85439           if (currentUser.Length > UNAMELEN) {
 0440            currentUser = currentUser.Substring(0, UNAMELEN);
 441          }
 85442          userName = currentUser;
 443        }
 85444      }
 445    }
 446
 447
 448    /// <summary>
 449    /// Get/set the entry's group name.
 450    /// </summary>
 451    /// <remarks>
 452    /// This is only directly relevant to unix systems.
 453    /// </remarks>
 454    public string GroupName {
 110455      get { return groupName; }
 456      set {
 166457         if (value == null) {
 1458          groupName = "None";
 1459        } else {
 165460          groupName = value;
 461        }
 165462      }
 463    }
 464
 465
 466    /// <summary>
 467    /// Get/set the entry's major device number.
 468    /// </summary>
 469    public int DevMajor {
 36470      get { return devMajor; }
 162471      set { devMajor = value; }
 472    }
 473
 474
 475    /// <summary>
 476    /// Get/set the entry's minor device number.
 477    /// </summary>
 478    public int DevMinor {
 34479      get { return devMinor; }
 162480      set { devMinor = value; }
 481    }
 482
 483    #endregion
 484
 485    #region ICloneable Members
 486    /// <summary>
 487    /// Create a new <see cref="TarHeader"/> that is a copy of the current instance.
 488    /// </summary>
 489    /// <returns>A new <see cref="Object"/> that is a copy of the current instance.</returns>
 490    public object Clone()
 491    {
 2492      return MemberwiseClone();
 493    }
 494    #endregion
 495
 496    /// <summary>
 497    /// Parse TarHeader information from a header buffer.
 498    /// </summary>
 499    /// <param name = "header">
 500    /// The tar entry header buffer to get information from.
 501    /// </param>
 502    public void ParseBuffer(byte[] header)
 503    {
 3504       if (header == null) {
 0505        throw new ArgumentNullException(nameof(header));
 506      }
 507
 3508      int offset = 0;
 509
 3510      name = ParseName(header, offset, NAMELEN).ToString();
 3511      offset += NAMELEN;
 512
 3513      mode = (int)ParseOctal(header, offset, MODELEN);
 3514      offset += MODELEN;
 515
 3516      UserId = (int)ParseOctal(header, offset, UIDLEN);
 3517      offset += UIDLEN;
 518
 3519      GroupId = (int)ParseOctal(header, offset, GIDLEN);
 3520      offset += GIDLEN;
 521
 3522      Size = ParseBinaryOrOctal(header, offset, SIZELEN);
 3523      offset += SIZELEN;
 524
 3525      ModTime = GetDateTimeFromCTime(ParseOctal(header, offset, MODTIMELEN));
 3526      offset += MODTIMELEN;
 527
 3528      checksum = (int)ParseOctal(header, offset, CHKSUMLEN);
 3529      offset += CHKSUMLEN;
 530
 3531      TypeFlag = header[offset++];
 532
 3533      LinkName = ParseName(header, offset, NAMELEN).ToString();
 3534      offset += NAMELEN;
 535
 3536      Magic = ParseName(header, offset, MAGICLEN).ToString();
 3537      offset += MAGICLEN;
 538
 3539       if (Magic == "ustar")
 540      {
 0541        Version = ParseName(header, offset, VERSIONLEN).ToString();
 0542        offset += VERSIONLEN;
 543
 0544        UserName = ParseName(header, offset, UNAMELEN).ToString();
 0545        offset += UNAMELEN;
 546
 0547        GroupName = ParseName(header, offset, GNAMELEN).ToString();
 0548        offset += GNAMELEN;
 549
 0550        DevMajor = (int) ParseOctal(header, offset, DEVLEN);
 0551        offset += DEVLEN;
 552
 0553        DevMinor = (int) ParseOctal(header, offset, DEVLEN);
 0554        offset += DEVLEN;
 555
 0556        string prefix = ParseName(header, offset, PREFIXLEN).ToString();
 0557         if (!string.IsNullOrEmpty(prefix)) Name = prefix + '/' + Name;
 558      }
 559
 3560      isChecksumValid = Checksum == TarHeader.MakeCheckSum(header);
 3561    }
 562
 563    /// <summary>
 564    /// 'Write' header information to buffer provided, updating the <see cref="Checksum">check sum</see>.
 565    /// </summary>
 566    /// <param name="outBuffer">output buffer for header information</param>
 567    public void WriteHeader(byte[] outBuffer)
 568    {
 70569       if (outBuffer == null) {
 0570        throw new ArgumentNullException(nameof(outBuffer));
 571      }
 572
 70573      int offset = 0;
 574
 70575      offset = GetNameBytes(Name, outBuffer, offset, NAMELEN);
 70576      offset = GetOctalBytes(mode, outBuffer, offset, MODELEN);
 70577      offset = GetOctalBytes(UserId, outBuffer, offset, UIDLEN);
 70578      offset = GetOctalBytes(GroupId, outBuffer, offset, GIDLEN);
 579
 70580      offset = GetBinaryOrOctalBytes(Size, outBuffer, offset, SIZELEN);
 70581      offset = GetOctalBytes(GetCTime(ModTime), outBuffer, offset, MODTIMELEN);
 582
 70583      int csOffset = offset;
 1260584       for (int c = 0; c < CHKSUMLEN; ++c) {
 560585        outBuffer[offset++] = (byte)' ';
 586      }
 587
 70588      outBuffer[offset++] = TypeFlag;
 589
 70590      offset = GetNameBytes(LinkName, outBuffer, offset, NAMELEN);
 70591      offset = GetAsciiBytes(Magic, 0, outBuffer, offset, MAGICLEN);
 70592      offset = GetNameBytes(Version, outBuffer, offset, VERSIONLEN);
 70593      offset = GetNameBytes(UserName, outBuffer, offset, UNAMELEN);
 70594      offset = GetNameBytes(GroupName, outBuffer, offset, GNAMELEN);
 595
 70596       if ((TypeFlag == LF_CHR) || (TypeFlag == LF_BLK)) {
 0597        offset = GetOctalBytes(DevMajor, outBuffer, offset, DEVLEN);
 0598        offset = GetOctalBytes(DevMinor, outBuffer, offset, DEVLEN);
 599      }
 600
 12880601       for (; offset < outBuffer.Length;) {
 12810602        outBuffer[offset++] = 0;
 603      }
 604
 70605      checksum = ComputeCheckSum(outBuffer);
 606
 70607      GetCheckSumOctalBytes(checksum, outBuffer, csOffset, CHKSUMLEN);
 70608      isChecksumValid = true;
 70609    }
 610
 611    /// <summary>
 612    /// Get a hash code for the current object.
 613    /// </summary>
 614    /// <returns>A hash code for the current object.</returns>
 615    public override int GetHashCode()
 616    {
 0617      return Name.GetHashCode();
 618    }
 619
 620    /// <summary>
 621    /// Determines if this instance is equal to the specified object.
 622    /// </summary>
 623    /// <param name="obj">The object to compare with.</param>
 624    /// <returns>true if the objects are equal, false otherwise.</returns>
 625    public override bool Equals(object obj)
 626    {
 29627      var localHeader = obj as TarHeader;
 628
 629      bool result;
 29630       if (localHeader != null) {
 29631        result = (name == localHeader.name)
 29632          && (mode == localHeader.mode)
 29633          && (UserId == localHeader.UserId)
 29634          && (GroupId == localHeader.GroupId)
 29635          && (Size == localHeader.Size)
 29636          && (ModTime == localHeader.ModTime)
 29637          && (Checksum == localHeader.Checksum)
 29638          && (TypeFlag == localHeader.TypeFlag)
 29639          && (LinkName == localHeader.LinkName)
 29640          && (Magic == localHeader.Magic)
 29641          && (Version == localHeader.Version)
 29642          && (UserName == localHeader.UserName)
 29643          && (GroupName == localHeader.GroupName)
 29644          && (DevMajor == localHeader.DevMajor)
 29645          && (DevMinor == localHeader.DevMinor);
 29646      } else {
 0647        result = false;
 648      }
 29649      return result;
 650    }
 651
 652    /// <summary>
 653    /// Set defaults for values used when constructing a TarHeader instance.
 654    /// </summary>
 655    /// <param name="userId">Value to apply as a default for userId.</param>
 656    /// <param name="userName">Value to apply as a default for userName.</param>
 657    /// <param name="groupId">Value to apply as a default for groupId.</param>
 658    /// <param name="groupName">Value to apply as a default for groupName.</param>
 659    static internal void SetValueDefaults(int userId, string userName, int groupId, string groupName)
 660    {
 0661      defaultUserId = userIdAsSet = userId;
 0662      defaultUser = userNameAsSet = userName;
 0663      defaultGroupId = groupIdAsSet = groupId;
 0664      defaultGroupName = groupNameAsSet = groupName;
 0665    }
 666
 667    static internal void RestoreSetValues()
 668    {
 0669      defaultUserId = userIdAsSet;
 0670      defaultUser = userNameAsSet;
 0671      defaultGroupId = groupIdAsSet;
 0672      defaultGroupName = groupNameAsSet;
 0673    }
 674
 675    // Return value that may be stored in octal or binary. Length must exceed 8.
 676    //
 677    static private long ParseBinaryOrOctal(byte[] header, int offset, int length)
 678    {
 3679       if (header[offset] >= 0x80) {
 680        // File sizes over 8GB are stored in 8 right-justified bytes of binary indicated by setting the high-order bit o
 0681        long result = 0;
 0682         for (int pos = length - 8; pos < length; pos++) {
 0683          result = result << 8 | header[offset + pos];
 684        }
 0685        return result;
 686      }
 3687      return ParseOctal(header, offset, length);
 688    }
 689
 690    /// <summary>
 691    /// Parse an octal string from a header buffer.
 692    /// </summary>
 693    /// <param name = "header">The header buffer from which to parse.</param>
 694    /// <param name = "offset">The offset into the buffer from which to parse.</param>
 695    /// <param name = "length">The number of header bytes to parse.</param>
 696    /// <returns>The long equivalent of the octal string.</returns>
 697    static public long ParseOctal(byte[] header, int offset, int length)
 698    {
 18699       if (header == null) {
 0700        throw new ArgumentNullException(nameof(header));
 701      }
 702
 18703      long result = 0;
 18704      bool stillPadding = true;
 705
 18706      int end = offset + length;
 330707       for (int i = offset; i < end; ++i) {
 165708         if (header[i] == 0) {
 709          break;
 710        }
 711
 147712         if (header[i] == (byte)' ' || header[i] == '0') {
 102713           if (stillPadding) {
 714            continue;
 715          }
 716
 15717           if (header[i] == (byte)' ') {
 718            break;
 719          }
 720        }
 721
 60722        stillPadding = false;
 723
 60724        result = (result << 3) + (header[i] - '0');
 725      }
 726
 18727      return result;
 728    }
 729
 730    /// <summary>
 731    /// Parse a name from a header buffer.
 732    /// </summary>
 733    /// <param name="header">
 734    /// The header buffer from which to parse.
 735    /// </param>
 736    /// <param name="offset">
 737    /// The offset into the buffer from which to parse.
 738    /// </param>
 739    /// <param name="length">
 740    /// The number of header bytes to parse.
 741    /// </param>
 742    /// <returns>
 743    /// The name parsed.
 744    /// </returns>
 745    static public StringBuilder ParseName(byte[] header, int offset, int length)
 746    {
 9747       if (header == null) {
 0748        throw new ArgumentNullException(nameof(header));
 749      }
 750
 9751       if (offset < 0) {
 0752        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be less than zero");
 753      }
 754
 9755       if (length < 0) {
 0756        throw new ArgumentOutOfRangeException(nameof(length), "Cannot be less than zero");
 757      }
 758
 9759       if (offset + length > header.Length) {
 0760        throw new ArgumentException("Exceeds header size", nameof(length));
 761      }
 762
 9763      var result = new StringBuilder(length);
 764
 108765       for (int i = offset; i < offset + length; ++i) {
 51766         if (header[i] == 0) {
 767          break;
 768        }
 45769        result.Append((char)header[i]);
 770      }
 771
 9772      return result;
 773    }
 774
 775    /// <summary>
 776    /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes
 777    /// </summary>
 778    /// <param name="name">The name to add</param>
 779    /// <param name="nameOffset">The offset of the first character</param>
 780    /// <param name="buffer">The buffer to add to</param>
 781    /// <param name="bufferOffset">The index of the first byte to add</param>
 782    /// <param name="length">The number of characters/bytes to add</param>
 783    /// <returns>The next free index in the <paramref name="buffer"/></returns>
 784    public static int GetNameBytes(StringBuilder name, int nameOffset, byte[] buffer, int bufferOffset, int length)
 785    {
 0786       if (name == null) {
 0787        throw new ArgumentNullException(nameof(name));
 788      }
 789
 0790       if (buffer == null) {
 0791        throw new ArgumentNullException(nameof(buffer));
 792      }
 793
 0794      return GetNameBytes(name.ToString(), nameOffset, buffer, bufferOffset, length);
 795    }
 796
 797    /// <summary>
 798    /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes
 799    /// </summary>
 800    /// <param name="name">The name to add</param>
 801    /// <param name="nameOffset">The offset of the first character</param>
 802    /// <param name="buffer">The buffer to add to</param>
 803    /// <param name="bufferOffset">The index of the first byte to add</param>
 804    /// <param name="length">The number of characters/bytes to add</param>
 805    /// <returns>The next free index in the <paramref name="buffer"/></returns>
 806    public static int GetNameBytes(string name, int nameOffset, byte[] buffer, int bufferOffset, int length)
 807    {
 350808       if (name == null) {
 0809        throw new ArgumentNullException(nameof(name));
 810      }
 811
 350812       if (buffer == null) {
 0813        throw new ArgumentNullException(nameof(buffer));
 814      }
 815
 816      int i;
 817
 2100818       for (i = 0 ; i < length && nameOffset + i < name.Length; ++i) {
 700819        buffer[bufferOffset + i] = (byte)name[nameOffset + i];
 820      }
 821
 36190822       for (; i < length; ++i) {
 17920823        buffer[bufferOffset + i] = 0;
 824      }
 825
 350826      return bufferOffset + length;
 827    }
 828
 829    /// <summary>
 830    /// Add an entry name to the buffer
 831    /// </summary>
 832    /// <param name="name">
 833    /// The name to add
 834    /// </param>
 835    /// <param name="buffer">
 836    /// The buffer to add to
 837    /// </param>
 838    /// <param name="offset">
 839    /// The offset into the buffer from which to start adding
 840    /// </param>
 841    /// <param name="length">
 842    /// The number of header bytes to add
 843    /// </param>
 844    /// <returns>
 845    /// The index of the next free byte in the buffer
 846    /// </returns>
 847    public static int GetNameBytes(StringBuilder name, byte[] buffer, int offset, int length)
 848    {
 849
 0850       if (name == null) {
 0851        throw new ArgumentNullException(nameof(name));
 852      }
 853
 0854       if (buffer == null) {
 0855        throw new ArgumentNullException(nameof(buffer));
 856      }
 857
 0858      return GetNameBytes(name.ToString(), 0, buffer, offset, length);
 859    }
 860
 861    /// <summary>
 862    /// Add an entry name to the buffer
 863    /// </summary>
 864    /// <param name="name">The name to add</param>
 865    /// <param name="buffer">The buffer to add to</param>
 866    /// <param name="offset">The offset into the buffer from which to start adding</param>
 867    /// <param name="length">The number of header bytes to add</param>
 868    /// <returns>The index of the next free byte in the buffer</returns>
 869    public static int GetNameBytes(string name, byte[] buffer, int offset, int length)
 870    {
 871
 350872       if (name == null) {
 0873        throw new ArgumentNullException(nameof(name));
 874      }
 875
 350876       if (buffer == null) {
 0877        throw new ArgumentNullException(nameof(buffer));
 878      }
 879
 350880      return GetNameBytes(name, 0, buffer, offset, length);
 881    }
 882
 883    /// <summary>
 884    /// Add a string to a buffer as a collection of ascii bytes.
 885    /// </summary>
 886    /// <param name="toAdd">The string to add</param>
 887    /// <param name="nameOffset">The offset of the first character to add.</param>
 888    /// <param name="buffer">The buffer to add to.</param>
 889    /// <param name="bufferOffset">The offset to start adding at.</param>
 890    /// <param name="length">The number of ascii characters to add.</param>
 891    /// <returns>The next free index in the buffer.</returns>
 892    public static int GetAsciiBytes(string toAdd, int nameOffset, byte[] buffer, int bufferOffset, int length)
 893    {
 70894       if (toAdd == null) {
 0895        throw new ArgumentNullException(nameof(toAdd));
 896      }
 897
 70898       if (buffer == null) {
 0899        throw new ArgumentNullException(nameof(buffer));
 900      }
 901
 980902       for (int i = 0; i < length && nameOffset + i < toAdd.Length; ++i) {
 420903        buffer[bufferOffset + i] = (byte)toAdd[nameOffset + i];
 904      }
 70905      return bufferOffset + length;
 906    }
 907
 908    /// <summary>
 909    /// Put an octal representation of a value into a buffer
 910    /// </summary>
 911    /// <param name = "value">
 912    /// the value to be converted to octal
 913    /// </param>
 914    /// <param name = "buffer">
 915    /// buffer to store the octal string
 916    /// </param>
 917    /// <param name = "offset">
 918    /// The offset into the buffer where the value starts
 919    /// </param>
 920    /// <param name = "length">
 921    /// The length of the octal string to create
 922    /// </param>
 923    /// <returns>
 924    /// The offset of the character next byte after the octal string
 925    /// </returns>
 926    public static int GetOctalBytes(long value, byte[] buffer, int offset, int length)
 927    {
 420928       if (buffer == null) {
 0929        throw new ArgumentNullException(nameof(buffer));
 930      }
 931
 420932      int localIndex = length - 1;
 933
 934      // Either a space or null is valid here.  We use NULL as per GNUTar
 420935      buffer[offset + localIndex] = 0;
 420936      --localIndex;
 937
 420938       if (value > 0) {
 4218939         for (long v = value; (localIndex >= 0) && (v > 0); --localIndex) {
 1831940          buffer[offset + localIndex] = (byte)((byte)'0' + (byte)(v & 7));
 1831941          v >>= 3;
 942        }
 943      }
 944
 3618945       for (; localIndex >= 0; --localIndex) {
 1599946        buffer[offset + localIndex] = (byte)'0';
 947      }
 948
 420949      return offset + length;
 950    }
 951
 952    /// <summary>
 953    /// Put an octal or binary representation of a value into a buffer
 954    /// </summary>
 955    /// <param name = "value">Value to be convert to octal</param>
 956    /// <param name = "buffer">The buffer to update</param>
 957    /// <param name = "offset">The offset into the buffer to store the value</param>
 958    /// <param name = "length">The length of the octal string. Must be 12.</param>
 959    /// <returns>Index of next byte</returns>
 960    private static int GetBinaryOrOctalBytes(long value, byte[] buffer, int offset, int length)
 961    {
 70962       if (value > 0x1FFFFFFFF) {  // Octal 77777777777 (11 digits)
 963                    // Put value as binary, right-justified into the buffer. Set high order bit of left-most byte.
 0964         for (int pos = length - 1; pos > 0; pos--) {
 0965          buffer[offset + pos] = (byte)value;
 0966          value = value >> 8;
 967        }
 0968        buffer[offset] = 0x80;
 0969        return offset + length;
 970      }
 70971      return GetOctalBytes(value, buffer, offset, length);
 972    }
 973
 974    /// <summary>
 975    /// Add the checksum integer to header buffer.
 976    /// </summary>
 977    /// <param name = "value"></param>
 978    /// <param name = "buffer">The header buffer to set the checksum for</param>
 979    /// <param name = "offset">The offset into the buffer for the checksum</param>
 980    /// <param name = "length">The number of header bytes to update.
 981    /// It's formatted differently from the other fields: it has 6 digits, a
 982    /// null, then a space -- rather than digits, a space, then a null.
 983    /// The final space is already there, from checksumming
 984    /// </param>
 985    /// <returns>The modified buffer offset</returns>
 986    static void GetCheckSumOctalBytes(long value, byte[] buffer, int offset, int length)
 987    {
 70988      GetOctalBytes(value, buffer, offset, length - 1);
 70989    }
 990
 991    /// <summary>
 992    /// Compute the checksum for a tar entry header.
 993    /// The checksum field must be all spaces prior to this happening
 994    /// </summary>
 995    /// <param name = "buffer">The tar entry's header buffer.</param>
 996    /// <returns>The computed checksum.</returns>
 997    static int ComputeCheckSum(byte[] buffer)
 998    {
 70999      int sum = 0;
 718201000       for (int i = 0; i < buffer.Length; ++i) {
 358401001        sum += buffer[i];
 1002      }
 701003      return sum;
 1004    }
 1005
 1006    /// <summary>
 1007    /// Make a checksum for a tar entry ignoring the checksum contents.
 1008    /// </summary>
 1009    /// <param name = "buffer">The tar entry's header buffer.</param>
 1010    /// <returns>The checksum for the buffer</returns>
 1011    static int MakeCheckSum(byte[] buffer)
 1012    {
 31013      int sum = 0;
 8941014       for (int i = 0; i < CHKSUMOFS; ++i) {
 4441015        sum += buffer[i];
 1016      }
 1017
 541018       for (int i = 0; i < CHKSUMLEN; ++i) {
 241019        sum += (byte)' ';
 1020      }
 1021
 21421022       for (int i = CHKSUMOFS + CHKSUMLEN; i < buffer.Length; ++i) {
 10681023        sum += buffer[i];
 1024      }
 31025      return sum;
 1026    }
 1027
 1028    static int GetCTime(DateTime dateTime)
 1029    {
 701030      return unchecked((int)((dateTime.Ticks - dateTime1970.Ticks) / timeConversionFactor));
 1031    }
 1032
 1033    static DateTime GetDateTimeFromCTime(long ticks)
 1034    {
 1035      DateTime result;
 1036
 1037      try {
 31038        result = new DateTime(dateTime1970.Ticks + ticks * timeConversionFactor);
 31039      } catch (ArgumentOutOfRangeException) {
 01040        result = dateTime1970;
 01041      }
 31042      return result;
 1043    }
 1044
 1045    #region Instance Fields
 1046    string name;
 1047    int mode;
 1048    int userId;
 1049    int groupId;
 1050    long size;
 1051    DateTime modTime;
 1052    int checksum;
 1053    bool isChecksumValid;
 1054    byte typeFlag;
 1055    string linkName;
 1056    string magic;
 1057    string version;
 1058    string userName;
 1059    string groupName;
 1060    int devMajor;
 1061    int devMinor;
 1062    #endregion
 1063
 1064    #region Class Fields
 1065    // Values used during recursive operations.
 1066    static internal int userIdAsSet;
 1067    static internal int groupIdAsSet;
 1068    static internal string userNameAsSet;
 11069    static internal string groupNameAsSet = "None";
 1070
 1071    static internal int defaultUserId;
 1072    static internal int defaultGroupId;
 11073    static internal string defaultGroupName = "None";
 1074    static internal string defaultUser;
 1075    #endregion
 1076  }
 1077}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_TarInputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_TarInputStream.htm new file mode 100644 index 000000000..2c6cec30a --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_TarInputStream.htm @@ -0,0 +1,688 @@ + + + + +ICSharpCode.SharpZipLib.Tar.TarInputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Tar.TarInputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarInputStream.cs
Covered lines:40
Uncovered lines:118
Coverable lines:158
Total lines:626
Line coverage:25.3%
Branch coverage:22%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)1100100
Flush()100
Seek(...)100
SetLength(...)100
Write(...)100
WriteByte(...)100
ReadByte()200
Read(...)1000
Close()1100100
SetEntryFactory(...)100
GetRecordSize()100
Skip(...)400
Mark(...)100
Reset()100
GetNextEntry()2042.8641.03
CopyEntryContents(...)200
SkipToNextEntry()200
CreateEntry(...)100
CreateEntryFromFile(...)100
CreateEntry(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarInputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Text;
 4
 5namespace ICSharpCode.SharpZipLib.Tar
 6{
 7  /// <summary>
 8  /// The TarInputStream reads a UNIX tar archive as an InputStream.
 9  /// methods are provided to position at each successive entry in
 10  /// the archive, and the read each entry as a normal input stream
 11  /// using read().
 12  /// </summary>
 13  public class TarInputStream : Stream
 14  {
 15    #region Constructors
 16    /// <summary>
 17    /// Construct a TarInputStream with default block factor
 18    /// </summary>
 19    /// <param name="inputStream">stream to source data from</param>
 20    public TarInputStream(Stream inputStream)
 421      : this(inputStream, TarBuffer.DefaultBlockFactor)
 22    {
 423    }
 24
 25    /// <summary>
 26    /// Construct a TarInputStream with user specified block factor
 27    /// </summary>
 28    /// <param name="inputStream">stream to source data from</param>
 29    /// <param name="blockFactor">block factor to apply to archive</param>
 530    public TarInputStream(Stream inputStream, int blockFactor)
 31    {
 532      this.inputStream = inputStream;
 533      tarBuffer = TarBuffer.CreateInputTarBuffer(inputStream, blockFactor);
 534    }
 35
 36    #endregion
 37
 38    /// <summary>
 39    /// Get/set flag indicating ownership of the underlying stream.
 40    /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
 41    /// </summary>
 42    public bool IsStreamOwner {
 043      get { return tarBuffer.IsStreamOwner; }
 244      set { tarBuffer.IsStreamOwner = value; }
 45    }
 46
 47    #region Stream Overrides
 48    /// <summary>
 49    /// Gets a value indicating whether the current stream supports reading
 50    /// </summary>
 51    public override bool CanRead {
 52      get {
 053        return inputStream.CanRead;
 54      }
 55    }
 56
 57    /// <summary>
 58    /// Gets a value indicating whether the current stream supports seeking
 59    /// This property always returns false.
 60    /// </summary>
 61    public override bool CanSeek {
 62      get {
 063        return false;
 64      }
 65    }
 66
 67    /// <summary>
 68    /// Gets a value indicating if the stream supports writing.
 69    /// This property always returns false.
 70    /// </summary>
 71    public override bool CanWrite {
 72      get {
 073        return false;
 74      }
 75    }
 76
 77    /// <summary>
 78    /// The length in bytes of the stream
 79    /// </summary>
 80    public override long Length {
 81      get {
 082        return inputStream.Length;
 83      }
 84    }
 85
 86    /// <summary>
 87    /// Gets or sets the position within the stream.
 88    /// Setting the Position is not supported and throws a NotSupportedExceptionNotSupportedException
 89    /// </summary>
 90    /// <exception cref="NotSupportedException">Any attempt to set position</exception>
 91    public override long Position {
 92      get {
 093        return inputStream.Position;
 94      }
 95      set {
 096        throw new NotSupportedException("TarInputStream Seek not supported");
 97      }
 98    }
 99
 100    /// <summary>
 101    /// Flushes the baseInputStream
 102    /// </summary>
 103    public override void Flush()
 104    {
 0105      inputStream.Flush();
 0106    }
 107
 108    /// <summary>
 109    /// Set the streams position.  This operation is not supported and will throw a NotSupportedException
 110    /// </summary>
 111    /// <param name="offset">The offset relative to the origin to seek to.</param>
 112    /// <param name="origin">The <see cref="SeekOrigin"/> to start seeking from.</param>
 113    /// <returns>The new position in the stream.</returns>
 114    /// <exception cref="NotSupportedException">Any access</exception>
 115    public override long Seek(long offset, SeekOrigin origin)
 116    {
 0117      throw new NotSupportedException("TarInputStream Seek not supported");
 118    }
 119
 120    /// <summary>
 121    /// Sets the length of the stream
 122    /// This operation is not supported and will throw a NotSupportedException
 123    /// </summary>
 124    /// <param name="value">The new stream length.</param>
 125    /// <exception cref="NotSupportedException">Any access</exception>
 126    public override void SetLength(long value)
 127    {
 0128      throw new NotSupportedException("TarInputStream SetLength not supported");
 129    }
 130
 131    /// <summary>
 132    /// Writes a block of bytes to this stream using data from a buffer.
 133    /// This operation is not supported and will throw a NotSupportedException
 134    /// </summary>
 135    /// <param name="buffer">The buffer containing bytes to write.</param>
 136    /// <param name="offset">The offset in the buffer of the frist byte to write.</param>
 137    /// <param name="count">The number of bytes to write.</param>
 138    /// <exception cref="NotSupportedException">Any access</exception>
 139    public override void Write(byte[] buffer, int offset, int count)
 140    {
 0141      throw new NotSupportedException("TarInputStream Write not supported");
 142    }
 143
 144    /// <summary>
 145    /// Writes a byte to the current position in the file stream.
 146    /// This operation is not supported and will throw a NotSupportedException
 147    /// </summary>
 148    /// <param name="value">The byte value to write.</param>
 149    /// <exception cref="NotSupportedException">Any access</exception>
 150    public override void WriteByte(byte value)
 151    {
 0152      throw new NotSupportedException("TarInputStream WriteByte not supported");
 153    }
 154    /// <summary>
 155    /// Reads a byte from the current tar archive entry.
 156    /// </summary>
 157    /// <returns>A byte cast to an int; -1 if the at the end of the stream.</returns>
 158    public override int ReadByte()
 159    {
 0160      byte[] oneByteBuffer = new byte[1];
 0161      int num = Read(oneByteBuffer, 0, 1);
 0162       if (num <= 0) {
 163        // return -1 to indicate that no byte was read.
 0164        return -1;
 165      }
 0166      return oneByteBuffer[0];
 167    }
 168
 169    /// <summary>
 170    /// Reads bytes from the current tar archive entry.
 171    ///
 172    /// This method is aware of the boundaries of the current
 173    /// entry in the archive and will deal with them appropriately
 174    /// </summary>
 175    /// <param name="buffer">
 176    /// The buffer into which to place bytes read.
 177    /// </param>
 178    /// <param name="offset">
 179    /// The offset at which to place bytes read.
 180    /// </param>
 181    /// <param name="count">
 182    /// The number of bytes to read.
 183    /// </param>
 184    /// <returns>
 185    /// The number of bytes read, or 0 at end of stream/EOF.
 186    /// </returns>
 187    public override int Read(byte[] buffer, int offset, int count)
 188    {
 0189       if (buffer == null) {
 0190        throw new ArgumentNullException(nameof(buffer));
 191      }
 192
 0193      int totalRead = 0;
 194
 0195       if (entryOffset >= entrySize) {
 0196        return 0;
 197      }
 198
 0199      long numToRead = count;
 200
 0201       if ((numToRead + entryOffset) > entrySize) {
 0202        numToRead = entrySize - entryOffset;
 203      }
 204
 0205       if (readBuffer != null) {
 0206         int sz = (numToRead > readBuffer.Length) ? readBuffer.Length : (int)numToRead;
 207
 0208        Array.Copy(readBuffer, 0, buffer, offset, sz);
 209
 0210         if (sz >= readBuffer.Length) {
 0211          readBuffer = null;
 0212        } else {
 0213          int newLen = readBuffer.Length - sz;
 0214          byte[] newBuf = new byte[newLen];
 0215          Array.Copy(readBuffer, sz, newBuf, 0, newLen);
 0216          readBuffer = newBuf;
 217        }
 218
 0219        totalRead += sz;
 0220        numToRead -= sz;
 0221        offset += sz;
 222      }
 223
 0224       while (numToRead > 0) {
 0225        byte[] rec = tarBuffer.ReadBlock();
 0226         if (rec == null) {
 227          // Unexpected EOF!
 0228          throw new TarException("unexpected EOF with " + numToRead + " bytes unread");
 229        }
 230
 0231        var sz = (int)numToRead;
 0232        int recLen = rec.Length;
 233
 0234         if (recLen > sz) {
 0235          Array.Copy(rec, 0, buffer, offset, sz);
 0236          readBuffer = new byte[recLen - sz];
 0237          Array.Copy(rec, sz, readBuffer, 0, recLen - sz);
 0238        } else {
 0239          sz = recLen;
 0240          Array.Copy(rec, 0, buffer, offset, recLen);
 241        }
 242
 0243        totalRead += sz;
 0244        numToRead -= sz;
 0245        offset += sz;
 246      }
 247
 0248      entryOffset += totalRead;
 249
 0250      return totalRead;
 251    }
 252
 253    /// <summary>
 254    /// Closes this stream. Calls the TarBuffer's close() method.
 255    /// The underlying stream is closed by the TarBuffer.
 256    /// </summary>
 257    public override void Close()
 258    {
 5259      tarBuffer.Close();
 5260    }
 261
 262    #endregion
 263
 264    /// <summary>
 265    /// Set the entry factory for this instance.
 266    /// </summary>
 267    /// <param name="factory">The factory for creating new entries</param>
 268    public void SetEntryFactory(IEntryFactory factory)
 269    {
 0270      entryFactory = factory;
 0271    }
 272
 273    /// <summary>
 274    /// Get the record size being used by this stream's TarBuffer.
 275    /// </summary>
 276    public int RecordSize {
 0277      get { return tarBuffer.RecordSize; }
 278    }
 279
 280    /// <summary>
 281    /// Get the record size being used by this stream's TarBuffer.
 282    /// </summary>
 283    /// <returns>
 284    /// TarBuffer record size.
 285    /// </returns>
 286    [Obsolete("Use RecordSize property instead")]
 287    public int GetRecordSize()
 288    {
 0289      return tarBuffer.RecordSize;
 290    }
 291
 292    /// <summary>
 293    /// Get the available data that can be read from the current
 294    /// entry in the archive. This does not indicate how much data
 295    /// is left in the entire archive, only in the current entry.
 296    /// This value is determined from the entry's size header field
 297    /// and the amount of data already read from the current entry.
 298    /// </summary>
 299    /// <returns>
 300    /// The number of available bytes for the current entry.
 301    /// </returns>
 302    public long Available {
 303      get {
 0304        return entrySize - entryOffset;
 305      }
 306    }
 307
 308    /// <summary>
 309    /// Skip bytes in the input buffer. This skips bytes in the
 310    /// current entry's data, not the entire archive, and will
 311    /// stop at the end of the current entry's data if the number
 312    /// to skip extends beyond that point.
 313    /// </summary>
 314    /// <param name="skipCount">
 315    /// The number of bytes to skip.
 316    /// </param>
 317    public void Skip(long skipCount)
 318    {
 319      // TODO: REVIEW efficiency of TarInputStream.Skip
 320      // This is horribly inefficient, but it ensures that we
 321      // properly skip over bytes via the TarBuffer...
 322      //
 0323      byte[] skipBuf = new byte[8 * 1024];
 324
 0325       for (long num = skipCount; num > 0;) {
 0326         int toRead = num > skipBuf.Length ? skipBuf.Length : (int)num;
 0327        int numRead = Read(skipBuf, 0, toRead);
 328
 0329         if (numRead == -1) {
 330          break;
 331        }
 332
 0333        num -= numRead;
 334      }
 0335    }
 336
 337    /// <summary>
 338    /// Return a value of true if marking is supported; false otherwise.
 339    /// </summary>
 340    /// <remarks>Currently marking is not supported, the return value is always false.</remarks>
 341    public bool IsMarkSupported {
 342      get {
 0343        return false;
 344      }
 345    }
 346
 347    /// <summary>
 348    /// Since we do not support marking just yet, we do nothing.
 349    /// </summary>
 350    /// <param name ="markLimit">
 351    /// The limit to mark.
 352    /// </param>
 353    public void Mark(int markLimit)
 354    {
 0355    }
 356
 357    /// <summary>
 358    /// Since we do not support marking just yet, we do nothing.
 359    /// </summary>
 360    public void Reset()
 361    {
 0362    }
 363
 364    /// <summary>
 365    /// Get the next entry in this tar archive. This will skip
 366    /// over any remaining data in the current entry, if there
 367    /// is one, and place the input stream at the header of the
 368    /// next entry, and read the header and instantiate a new
 369    /// TarEntry from the header bytes and return that entry.
 370    /// If there are no more entries in the archive, null will
 371    /// be returned to indicate that the end of the archive has
 372    /// been reached.
 373    /// </summary>
 374    /// <returns>
 375    /// The next TarEntry in the archive, or null.
 376    /// </returns>
 377    public TarEntry GetNextEntry()
 378    {
 3379       if (hasHitEOF) {
 0380        return null;
 381      }
 382
 3383       if (currentEntry != null) {
 0384        SkipToNextEntry();
 385      }
 386
 3387      byte[] headerBuf = tarBuffer.ReadBlock();
 388
 3389       if (headerBuf == null) {
 0390        hasHitEOF = true;
 0391      } else
 3392        hasHitEOF |= TarBuffer.IsEndOfArchiveBlock(headerBuf);
 393
 3394       if (hasHitEOF) {
 1395        currentEntry = null;
 1396      } else {
 397        try {
 2398          var header = new TarHeader();
 2399          header.ParseBuffer(headerBuf);
 2400           if (!header.IsChecksumValid) {
 1401            throw new TarException("Header checksum is invalid");
 402          }
 1403          this.entryOffset = 0;
 1404          this.entrySize = header.Size;
 405
 1406          StringBuilder longName = null;
 407
 1408           if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME) {
 409
 0410            byte[] nameBuffer = new byte[TarBuffer.BlockSize];
 0411            long numToRead = this.entrySize;
 412
 0413            longName = new StringBuilder();
 414
 0415             while (numToRead > 0) {
 0416               int numRead = this.Read(nameBuffer, 0, (numToRead > nameBuffer.Length ? nameBuffer.Length : (int)numToRead
 417
 0418               if (numRead == -1) {
 0419                throw new InvalidHeaderException("Failed to read long name entry");
 420              }
 421
 0422              longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString());
 0423              numToRead -= numRead;
 424            }
 425
 0426            SkipToNextEntry();
 0427            headerBuf = this.tarBuffer.ReadBlock();
 1428           } else if (header.TypeFlag == TarHeader.LF_GHDR) {  // POSIX global extended header
 429                                    // Ignore things we dont understand completely for now
 0430            SkipToNextEntry();
 0431            headerBuf = this.tarBuffer.ReadBlock();
 1432           } else if (header.TypeFlag == TarHeader.LF_XHDR) {  // POSIX extended header
 433                                    // Ignore things we dont understand completely for now
 0434            SkipToNextEntry();
 0435            headerBuf = this.tarBuffer.ReadBlock();
 1436           } else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR) {
 437            // TODO: could show volume name when verbose
 0438            SkipToNextEntry();
 0439            headerBuf = this.tarBuffer.ReadBlock();
 1440           } else if (header.TypeFlag != TarHeader.LF_NORMAL &&
 1441                 header.TypeFlag != TarHeader.LF_OLDNORM &&
 1442                 header.TypeFlag != TarHeader.LF_LINK &&
 1443                 header.TypeFlag != TarHeader.LF_SYMLINK &&
 1444                 header.TypeFlag != TarHeader.LF_DIR) {
 445            // Ignore things we dont understand completely for now
 0446            SkipToNextEntry();
 0447            headerBuf = tarBuffer.ReadBlock();
 448          }
 449
 1450           if (entryFactory == null) {
 1451            currentEntry = new TarEntry(headerBuf);
 1452             if (longName != null) {
 0453              currentEntry.Name = longName.ToString();
 454            }
 0455          } else {
 0456            currentEntry = entryFactory.CreateEntry(headerBuf);
 457          }
 458
 459          // Magic was checked here for 'ustar' but there are multiple valid possibilities
 460          // so this is not done anymore.
 461
 1462          entryOffset = 0;
 463
 464          // TODO: Review How do we resolve this discrepancy?!
 1465          entrySize = this.currentEntry.Size;
 1466        } catch (InvalidHeaderException ex) {
 0467          entrySize = 0;
 0468          entryOffset = 0;
 0469          currentEntry = null;
 0470          string errorText = string.Format("Bad header in record {0} block {1} {2}",
 0471            tarBuffer.CurrentRecord, tarBuffer.CurrentBlock, ex.Message);
 0472          throw new InvalidHeaderException(errorText);
 473        }
 474      }
 2475      return currentEntry;
 476    }
 477
 478    /// <summary>
 479    /// Copies the contents of the current tar archive entry directly into
 480    /// an output stream.
 481    /// </summary>
 482    /// <param name="outputStream">
 483    /// The OutputStream into which to write the entry's data.
 484    /// </param>
 485    public void CopyEntryContents(Stream outputStream)
 486    {
 0487      byte[] tempBuffer = new byte[32 * 1024];
 488
 0489      while (true) {
 0490        int numRead = Read(tempBuffer, 0, tempBuffer.Length);
 0491         if (numRead <= 0) {
 492          break;
 493        }
 0494        outputStream.Write(tempBuffer, 0, numRead);
 495      }
 0496    }
 497
 498    void SkipToNextEntry()
 499    {
 0500      long numToSkip = entrySize - entryOffset;
 501
 0502       if (numToSkip > 0) {
 0503        Skip(numToSkip);
 504      }
 505
 0506      readBuffer = null;
 0507    }
 508
 509    /// <summary>
 510    /// This interface is provided, along with the method <see cref="SetEntryFactory"/>, to allow
 511    /// the programmer to have their own <see cref="TarEntry"/> subclass instantiated for the
 512    /// entries return from <see cref="GetNextEntry"/>.
 513    /// </summary>
 514    public interface IEntryFactory
 515    {
 516      /// <summary>
 517      /// Create an entry based on name alone
 518      /// </summary>
 519      /// <param name="name">
 520      /// Name of the new EntryPointNotFoundException to create
 521      /// </param>
 522      /// <returns>created TarEntry or descendant class</returns>
 523      TarEntry CreateEntry(string name);
 524
 525      /// <summary>
 526      /// Create an instance based on an actual file
 527      /// </summary>
 528      /// <param name="fileName">
 529      /// Name of file to represent in the entry
 530      /// </param>
 531      /// <returns>
 532      /// Created TarEntry or descendant class
 533      /// </returns>
 534      TarEntry CreateEntryFromFile(string fileName);
 535
 536      /// <summary>
 537      /// Create a tar entry based on the header information passed
 538      /// </summary>
 539      /// <param name="headerBuffer">
 540      /// Buffer containing header information to create an an entry from.
 541      /// </param>
 542      /// <returns>
 543      /// Created TarEntry or descendant class
 544      /// </returns>
 545      TarEntry CreateEntry(byte[] headerBuffer);
 546    }
 547
 548    /// <summary>
 549    /// Standard entry factory class creating instances of the class TarEntry
 550    /// </summary>
 551    public class EntryFactoryAdapter : IEntryFactory
 552    {
 553      /// <summary>
 554      /// Create a <see cref="TarEntry"/> based on named
 555      /// </summary>
 556      /// <param name="name">The name to use for the entry</param>
 557      /// <returns>A new <see cref="TarEntry"/></returns>
 558      public TarEntry CreateEntry(string name)
 559      {
 0560        return TarEntry.CreateTarEntry(name);
 561      }
 562
 563      /// <summary>
 564      /// Create a tar entry with details obtained from <paramref name="fileName">file</paramref>
 565      /// </summary>
 566      /// <param name="fileName">The name of the file to retrieve details from.</param>
 567      /// <returns>A new <see cref="TarEntry"/></returns>
 568      public TarEntry CreateEntryFromFile(string fileName)
 569      {
 0570        return TarEntry.CreateEntryFromFile(fileName);
 571      }
 572
 573      /// <summary>
 574      /// Create an entry based on details in <paramref name="headerBuffer">header</paramref>
 575      /// </summary>
 576      /// <param name="headerBuffer">The buffer containing entry details.</param>
 577      /// <returns>A new <see cref="TarEntry"/></returns>
 578      public TarEntry CreateEntry(byte[] headerBuffer)
 579      {
 0580        return new TarEntry(headerBuffer);
 581      }
 582    }
 583
 584    #region Instance Fields
 585    /// <summary>
 586    /// Flag set when last block has been read
 587    /// </summary>
 588    protected bool hasHitEOF;
 589
 590    /// <summary>
 591    /// Size of this entry as recorded in header
 592    /// </summary>
 593    protected long entrySize;
 594
 595    /// <summary>
 596    /// Number of bytes read for this entry so far
 597    /// </summary>
 598    protected long entryOffset;
 599
 600    /// <summary>
 601    /// Buffer used with calls to <code>Read()</code>
 602    /// </summary>
 603    protected byte[] readBuffer;
 604
 605    /// <summary>
 606    /// Working buffer
 607    /// </summary>
 608    protected TarBuffer tarBuffer;
 609
 610    /// <summary>
 611    /// Current entry being read
 612    /// </summary>
 613    TarEntry currentEntry;
 614
 615    /// <summary>
 616    /// Factory used to create TarEntry or descendant class instance
 617    /// </summary>
 618    protected IEntryFactory entryFactory;
 619
 620    /// <summary>
 621    /// Stream used as the source of input data.
 622    /// </summary>
 623    readonly Stream inputStream;
 624    #endregion
 625  }
 626}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_TarOutputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_TarOutputStream.htm new file mode 100644 index 000000000..7cf123c3a --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_TarOutputStream.htm @@ -0,0 +1,498 @@ + + + + +ICSharpCode.SharpZipLib.Tar.TarOutputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Tar.TarOutputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarOutputStream.cs
Covered lines:64
Uncovered lines:54
Coverable lines:118
Total lines:442
Line coverage:54.2%
Branch coverage:58.3%
+

Metrics

+ + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)287.566.67
Seek(...)100
SetLength(...)100
ReadByte()100
Read(...)100
Flush()1100100
Finish()2100100
Close()210066.67
GetRecordSize()100
PutNextEntry(...)526.9244.44
CloseEntry()377.7860
WriteByte(...)1100100
Write(...)1059.4668.42
WriteEofBlock()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Tar\TarOutputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Tar
 5{
 6  /// <summary>
 7  /// The TarOutputStream writes a UNIX tar archive as an OutputStream.
 8  /// Methods are provided to put entries, and then write their contents
 9  /// by writing to this stream using write().
 10  /// </summary>
 11  /// public
 12  public class TarOutputStream : Stream
 13  {
 14    #region Constructors
 15    /// <summary>
 16    /// Construct TarOutputStream using default block factor
 17    /// </summary>
 18    /// <param name="outputStream">stream to write to</param>
 19    public TarOutputStream(Stream outputStream)
 320      : this(outputStream, TarBuffer.DefaultBlockFactor)
 21    {
 322    }
 23
 24    /// <summary>
 25    /// Construct TarOutputStream with user specified block factor
 26    /// </summary>
 27    /// <param name="outputStream">stream to write to</param>
 28    /// <param name="blockFactor">blocking factor</param>
 7329    public TarOutputStream(Stream outputStream, int blockFactor)
 30    {
 7331       if (outputStream == null) {
 032        throw new ArgumentNullException(nameof(outputStream));
 33      }
 34
 7335      this.outputStream = outputStream;
 7336      buffer = TarBuffer.CreateOutputTarBuffer(outputStream, blockFactor);
 37
 7338      assemblyBuffer = new byte[TarBuffer.BlockSize];
 7339      blockBuffer = new byte[TarBuffer.BlockSize];
 7340    }
 41    #endregion
 42
 43    /// <summary>
 44    /// Get/set flag indicating ownership of the underlying stream.
 45    /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
 46    /// </summary>
 47    public bool IsStreamOwner {
 048      get { return buffer.IsStreamOwner; }
 249      set { buffer.IsStreamOwner = value; }
 50    }
 51
 52    /// <summary>
 53    /// true if the stream supports reading; otherwise, false.
 54    /// </summary>
 55    public override bool CanRead {
 56      get {
 057        return outputStream.CanRead;
 58      }
 59    }
 60
 61    /// <summary>
 62    /// true if the stream supports seeking; otherwise, false.
 63    /// </summary>
 64    public override bool CanSeek {
 65      get {
 066        return outputStream.CanSeek;
 67      }
 68    }
 69
 70    /// <summary>
 71    /// true if stream supports writing; otherwise, false.
 72    /// </summary>
 73    public override bool CanWrite {
 74      get {
 075        return outputStream.CanWrite;
 76      }
 77    }
 78
 79    /// <summary>
 80    /// length of stream in bytes
 81    /// </summary>
 82    public override long Length {
 83      get {
 084        return outputStream.Length;
 85      }
 86    }
 87
 88    /// <summary>
 89    /// gets or sets the position within the current stream.
 90    /// </summary>
 91    public override long Position {
 92      get {
 093        return outputStream.Position;
 94      }
 95      set {
 096        outputStream.Position = value;
 097      }
 98    }
 99
 100    /// <summary>
 101    /// set the position within the current stream
 102    /// </summary>
 103    /// <param name="offset">The offset relative to the <paramref name="origin"/> to seek to</param>
 104    /// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
 105    /// <returns>The new position in the stream.</returns>
 106    public override long Seek(long offset, SeekOrigin origin)
 107    {
 0108      return outputStream.Seek(offset, origin);
 109    }
 110
 111    /// <summary>
 112    /// Set the length of the current stream
 113    /// </summary>
 114    /// <param name="value">The new stream length.</param>
 115    public override void SetLength(long value)
 116    {
 0117      outputStream.SetLength(value);
 0118    }
 119
 120    /// <summary>
 121    /// Read a byte from the stream and advance the position within the stream
 122    /// by one byte or returns -1 if at the end of the stream.
 123    /// </summary>
 124    /// <returns>The byte value or -1 if at end of stream</returns>
 125    public override int ReadByte()
 126    {
 0127      return outputStream.ReadByte();
 128    }
 129
 130    /// <summary>
 131    /// read bytes from the current stream and advance the position within the
 132    /// stream by the number of bytes read.
 133    /// </summary>
 134    /// <param name="buffer">The buffer to store read bytes in.</param>
 135    /// <param name="offset">The index into the buffer to being storing bytes at.</param>
 136    /// <param name="count">The desired number of bytes to read.</param>
 137    /// <returns>The total number of bytes read, or zero if at the end of the stream.
 138    /// The number of bytes may be less than the <paramref name="count">count</paramref>
 139    /// requested if data is not avialable.</returns>
 140    public override int Read(byte[] buffer, int offset, int count)
 141    {
 0142      return outputStream.Read(buffer, offset, count);
 143    }
 144
 145    /// <summary>
 146    /// All buffered data is written to destination
 147    /// </summary>
 148    public override void Flush()
 149    {
 1150      outputStream.Flush();
 1151    }
 152
 153    /// <summary>
 154    /// Ends the TAR archive without closing the underlying OutputStream.
 155    /// The result is that the EOF block of nulls is written.
 156    /// </summary>
 157    public void Finish()
 158    {
 73159       if (IsEntryOpen) {
 5160        CloseEntry();
 161      }
 73162      WriteEofBlock();
 73163    }
 164
 165    /// <summary>
 166    /// Ends the TAR archive and closes the underlying OutputStream.
 167    /// </summary>
 168    /// <remarks>This means that Finish() is called followed by calling the
 169    /// TarBuffer's Close().</remarks>
 170    public override void Close()
 171    {
 73172       if (!isClosed) {
 73173        isClosed = true;
 73174        Finish();
 73175        buffer.Close();
 176      }
 73177    }
 178
 179    /// <summary>
 180    /// Get the record size being used by this stream's TarBuffer.
 181    /// </summary>
 182    public int RecordSize {
 1183      get { return buffer.RecordSize; }
 184    }
 185
 186    /// <summary>
 187    /// Get the record size being used by this stream's TarBuffer.
 188    /// </summary>
 189    /// <returns>
 190    /// The TarBuffer record size.
 191    /// </returns>
 192    [Obsolete("Use RecordSize property instead")]
 193    public int GetRecordSize()
 194    {
 0195      return buffer.RecordSize;
 196    }
 197
 198    /// <summary>
 199    /// Get a value indicating wether an entry is open, requiring more data to be written.
 200    /// </summary>
 201    bool IsEntryOpen {
 73202      get { return (currBytes < currSize); }
 203
 204    }
 205
 206    /// <summary>
 207    /// Put an entry on the output stream. This writes the entry's
 208    /// header and positions the output stream for writing
 209    /// the contents of the entry. Once this method is called, the
 210    /// stream is ready for calls to write() to write the entry's
 211    /// contents. Once the contents are written, closeEntry()
 212    /// <B>MUST</B> be called to ensure that all buffered data
 213    /// is completely written to the output stream.
 214    /// </summary>
 215    /// <param name="entry">
 216    /// The TarEntry to be written to the archive.
 217    /// </param>
 218    public void PutNextEntry(TarEntry entry)
 219    {
 70220       if (entry == null) {
 0221        throw new ArgumentNullException(nameof(entry));
 222      }
 223
 70224       if (entry.TarHeader.Name.Length > TarHeader.NAMELEN) {
 0225        var longHeader = new TarHeader();
 0226        longHeader.TypeFlag = TarHeader.LF_GNU_LONGNAME;
 0227        longHeader.Name = longHeader.Name + "././@LongLink";
 0228        longHeader.Mode = 420;//644 by default
 0229        longHeader.UserId = entry.UserId;
 0230        longHeader.GroupId = entry.GroupId;
 0231        longHeader.GroupName = entry.GroupName;
 0232        longHeader.UserName = entry.UserName;
 0233        longHeader.LinkName = "";
 0234        longHeader.Size = entry.TarHeader.Name.Length + 1;  // Plus one to avoid dropping last char
 235
 0236        longHeader.WriteHeader(blockBuffer);
 0237        buffer.WriteBlock(blockBuffer);  // Add special long filename header block
 238
 0239        int nameCharIndex = 0;
 240
 0241         while (nameCharIndex < entry.TarHeader.Name.Length) {
 0242          Array.Clear(blockBuffer, 0, blockBuffer.Length);
 0243          TarHeader.GetAsciiBytes(entry.TarHeader.Name, nameCharIndex, this.blockBuffer, 0, TarBuffer.BlockSize);
 0244          nameCharIndex += TarBuffer.BlockSize;
 0245          buffer.WriteBlock(blockBuffer);
 246        }
 247      }
 248
 70249      entry.WriteEntryHeader(blockBuffer);
 70250      buffer.WriteBlock(blockBuffer);
 251
 70252      currBytes = 0;
 253
 70254       currSize = entry.IsDirectory ? 0 : entry.Size;
 70255    }
 256
 257    /// <summary>
 258    /// Close an entry. This method MUST be called for all file
 259    /// entries that contain data. The reason is that we must
 260    /// buffer data written to the stream in order to satisfy
 261    /// the buffer's block based writes. Thus, there may be
 262    /// data fragments still being assembled that must be written
 263    /// to the output stream before this entry is closed and the
 264    /// next entry written.
 265    /// </summary>
 266    public void CloseEntry()
 267    {
 5268       if (assemblyBufferLength > 0) {
 5269        Array.Clear(assemblyBuffer, assemblyBufferLength, assemblyBuffer.Length - assemblyBufferLength);
 270
 5271        buffer.WriteBlock(assemblyBuffer);
 272
 5273        currBytes += assemblyBufferLength;
 5274        assemblyBufferLength = 0;
 275      }
 276
 5277       if (currBytes < currSize) {
 0278        string errorText = string.Format(
 0279          "Entry closed at '{0}' before the '{1}' bytes specified in the header were written",
 0280          currBytes, currSize);
 0281        throw new TarException(errorText);
 282      }
 5283    }
 284
 285    /// <summary>
 286    /// Writes a byte to the current tar archive entry.
 287    /// This method simply calls Write(byte[], int, int).
 288    /// </summary>
 289    /// <param name="value">
 290    /// The byte to be written.
 291    /// </param>
 292    public override void WriteByte(byte value)
 293    {
 45294      Write(new byte[] { value }, 0, 1);
 45295    }
 296
 297    /// <summary>
 298    /// Writes bytes to the current tar archive entry. This method
 299    /// is aware of the current entry and will throw an exception if
 300    /// you attempt to write bytes past the length specified for the
 301    /// current entry. The method is also (painfully) aware of the
 302    /// record buffering required by TarBuffer, and manages buffers
 303    /// that are not a multiple of recordsize in length, including
 304    /// assembling records from small buffers.
 305    /// </summary>
 306    /// <param name = "buffer">
 307    /// The buffer to write to the archive.
 308    /// </param>
 309    /// <param name = "offset">
 310    /// The offset in the buffer from which to get bytes.
 311    /// </param>
 312    /// <param name = "count">
 313    /// The number of bytes to write.
 314    /// </param>
 315    public override void Write(byte[] buffer, int offset, int count)
 316    {
 4087317       if (buffer == null) {
 0318        throw new ArgumentNullException(nameof(buffer));
 319      }
 320
 4087321       if (offset < 0) {
 0322        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");
 323      }
 324
 4087325       if (buffer.Length - offset < count) {
 0326        throw new ArgumentException("offset and count combination is invalid");
 327      }
 328
 4087329       if (count < 0) {
 0330        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");
 331      }
 332
 4087333       if ((currBytes + count) > currSize) {
 0334        string errorText = string.Format("request to write '{0}' bytes exceeds size in header of '{1}' bytes",
 0335          count, this.currSize);
 0336        throw new ArgumentOutOfRangeException(nameof(count), errorText);
 337      }
 338
 339      //
 340      // We have to deal with assembly!!!
 341      // The programmer can be writing little 32 byte chunks for all
 342      // we know, and we must assemble complete blocks for writing.
 343      // TODO  REVIEW Maybe this should be in TarBuffer? Could that help to
 344      //        eliminate some of the buffer copying.
 345      //
 4087346       if (assemblyBufferLength > 0) {
 40347         if ((assemblyBufferLength + count) >= blockBuffer.Length) {
 0348          int aLen = blockBuffer.Length - assemblyBufferLength;
 349
 0350          Array.Copy(assemblyBuffer, 0, blockBuffer, 0, assemblyBufferLength);
 0351          Array.Copy(buffer, offset, blockBuffer, assemblyBufferLength, aLen);
 352
 0353          this.buffer.WriteBlock(blockBuffer);
 354
 0355          currBytes += blockBuffer.Length;
 356
 0357          offset += aLen;
 0358          count -= aLen;
 359
 0360          assemblyBufferLength = 0;
 0361        } else {
 40362          Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count);
 40363          offset += count;
 40364          assemblyBufferLength += count;
 40365          count -= count;
 366        }
 367      }
 368
 369      //
 370      // When we get here we have EITHER:
 371      //   o An empty "assembly" buffer.
 372      //   o No bytes to write (count == 0)
 373      //
 8129374       while (count > 0) {
 4047375         if (count < blockBuffer.Length) {
 5376          Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count);
 5377          assemblyBufferLength += count;
 5378          break;
 379        }
 380
 4042381        this.buffer.WriteBlock(buffer, offset);
 382
 4042383        int bufferLength = blockBuffer.Length;
 4042384        currBytes += bufferLength;
 4042385        count -= bufferLength;
 4042386        offset += bufferLength;
 387      }
 4082388    }
 389
 390    /// <summary>
 391    /// Write an EOF (end of archive) block to the tar archive.
 392    /// An EOF block consists of all zeros.
 393    /// </summary>
 394    void WriteEofBlock()
 395    {
 73396      Array.Clear(blockBuffer, 0, blockBuffer.Length);
 73397      buffer.WriteBlock(blockBuffer);
 73398    }
 399
 400    #region Instance Fields
 401    /// <summary>
 402    /// bytes written for this entry so far
 403    /// </summary>
 404    long currBytes;
 405
 406    /// <summary>
 407    /// current 'Assembly' buffer length
 408    /// </summary>
 409    int assemblyBufferLength;
 410
 411    /// <summary>
 412    /// Flag indicating wether this instance has been closed or not.
 413    /// </summary>
 414    bool isClosed;
 415
 416    /// <summary>
 417    /// Size for the current entry
 418    /// </summary>
 419    protected long currSize;
 420
 421    /// <summary>
 422    /// single block working buffer
 423    /// </summary>
 424    protected byte[] blockBuffer;
 425
 426    /// <summary>
 427    /// 'Assembly' buffer used to assemble data before writing
 428    /// </summary>
 429    protected byte[] assemblyBuffer;
 430
 431    /// <summary>
 432    /// TarBuffer used to provide correct blocking factor
 433    /// </summary>
 434    protected TarBuffer buffer;
 435
 436    /// <summary>
 437    /// the destination stream for the archive contents
 438    /// </summary>
 439    protected Stream outputStream;
 440    #endregion
 441  }
 442}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_TestStatus.htm b/docs/opencover/ICSharpCode.SharpZipLib_TestStatus.htm new file mode 100644 index 000000000..dca53c13e --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_TestStatus.htm @@ -0,0 +1,4308 @@ + + + + +ICSharpCode.SharpZipLib.Zip.TestStatus - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.TestStatus
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs
Covered lines:7
Uncovered lines:13
Coverable lines:20
Total lines:4263
Line coverage:35%
+

Metrics

+ + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
AddError()1100100
SetOperation(...)100
SetEntry(...)100
SetBytesTested(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.IO;
 4using System.Text;
 5using System.Globalization;
 6using System.Security.Cryptography;
 7using ICSharpCode.SharpZipLib.Encryption;
 8using ICSharpCode.SharpZipLib.Core;
 9using ICSharpCode.SharpZipLib.Checksum;
 10using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 11using ICSharpCode.SharpZipLib.Zip.Compression;
 12
 13namespace ICSharpCode.SharpZipLib.Zip
 14{
 15  #region Keys Required Event Args
 16  /// <summary>
 17  /// Arguments used with KeysRequiredEvent
 18  /// </summary>
 19  public class KeysRequiredEventArgs : EventArgs
 20  {
 21    #region Constructors
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 24    /// </summary>
 25    /// <param name="name">The name of the file for which keys are required.</param>
 26    public KeysRequiredEventArgs(string name)
 27    {
 28      fileName = name;
 29    }
 30
 31    /// <summary>
 32    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 33    /// </summary>
 34    /// <param name="name">The name of the file for which keys are required.</param>
 35    /// <param name="keyValue">The current key value.</param>
 36    public KeysRequiredEventArgs(string name, byte[] keyValue)
 37    {
 38      fileName = name;
 39      key = keyValue;
 40    }
 41
 42    #endregion
 43    #region Properties
 44    /// <summary>
 45    /// Gets the name of the file for which keys are required.
 46    /// </summary>
 47    public string FileName {
 48      get { return fileName; }
 49    }
 50
 51    /// <summary>
 52    /// Gets or sets the key value
 53    /// </summary>
 54    public byte[] Key {
 55      get { return key; }
 56      set { key = value; }
 57    }
 58    #endregion
 59
 60    #region Instance Fields
 61    string fileName;
 62    byte[] key;
 63    #endregion
 64  }
 65  #endregion
 66
 67  #region Test Definitions
 68  /// <summary>
 69  /// The strategy to apply to testing.
 70  /// </summary>
 71  public enum TestStrategy
 72  {
 73    /// <summary>
 74    /// Find the first error only.
 75    /// </summary>
 76    FindFirstError,
 77    /// <summary>
 78    /// Find all possible errors.
 79    /// </summary>
 80    FindAllErrors,
 81  }
 82
 83  /// <summary>
 84  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.
 85  /// </summary>
 86  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 87  public enum TestOperation
 88  {
 89    /// <summary>
 90    /// Setting up testing.
 91    /// </summary>
 92    Initialising,
 93
 94    /// <summary>
 95    /// Testing an individual entries header
 96    /// </summary>
 97    EntryHeader,
 98
 99    /// <summary>
 100    /// Testing an individual entries data
 101    /// </summary>
 102    EntryData,
 103
 104    /// <summary>
 105    /// Testing an individual entry has completed.
 106    /// </summary>
 107    EntryComplete,
 108
 109    /// <summary>
 110    /// Running miscellaneous tests
 111    /// </summary>
 112    MiscellaneousTests,
 113
 114    /// <summary>
 115    /// Testing is complete
 116    /// </summary>
 117    Complete,
 118  }
 119
 120  /// <summary>
 121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.
 122  /// </summary>
 123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 124  public class TestStatus
 125  {
 126    #region Constructors
 127    /// <summary>
 128    /// Initialise a new instance of <see cref="TestStatus"/>
 129    /// </summary>
 130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>
 96131    public TestStatus(ZipFile file)
 132    {
 96133      file_ = file;
 96134    }
 135    #endregion
 136
 137    #region Properties
 138
 139    /// <summary>
 140    /// Get the current <see cref="TestOperation"/> in progress.
 141    /// </summary>
 142    public TestOperation Operation {
 0143      get { return operation_; }
 144    }
 145
 146    /// <summary>
 147    /// Get the <see cref="ZipFile"/> this status is applicable to.
 148    /// </summary>
 149    public ZipFile File {
 0150      get { return file_; }
 151    }
 152
 153    /// <summary>
 154    /// Get the current/last entry tested.
 155    /// </summary>
 156    public ZipEntry Entry {
 0157      get { return entry_; }
 158    }
 159
 160    /// <summary>
 161    /// Get the number of errors detected so far.
 162    /// </summary>
 163    public int ErrorCount {
 96164      get { return errorCount_; }
 165    }
 166
 167    /// <summary>
 168    /// Get the number of bytes tested so far for the current entry.
 169    /// </summary>
 170    public long BytesTested {
 0171      get { return bytesTested_; }
 172    }
 173
 174    /// <summary>
 175    /// Get a value indicating wether the last entry test was valid.
 176    /// </summary>
 177    public bool EntryValid {
 0178      get { return entryValid_; }
 179    }
 180    #endregion
 181
 182    #region Internal API
 183    internal void AddError()
 184    {
 1185      errorCount_++;
 1186      entryValid_ = false;
 1187    }
 188
 189    internal void SetOperation(TestOperation operation)
 190    {
 0191      operation_ = operation;
 0192    }
 193
 194    internal void SetEntry(ZipEntry entry)
 195    {
 0196      entry_ = entry;
 0197      entryValid_ = true;
 0198      bytesTested_ = 0;
 0199    }
 200
 201    internal void SetBytesTested(long value)
 202    {
 0203      bytesTested_ = value;
 0204    }
 205    #endregion
 206
 207    #region Instance Fields
 208    ZipFile file_;
 209    ZipEntry entry_;
 210    bool entryValid_;
 211    int errorCount_;
 212    long bytesTested_;
 213    TestOperation operation_;
 214    #endregion
 215  }
 216
 217  /// <summary>
 218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if
 219  /// </summary>
 220  /// <remarks>If the message is non-null an error has occured.  If the message is null
 221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>
 222  public delegate void ZipTestResultHandler(TestStatus status, string message);
 223  #endregion
 224
 225  #region Update Definitions
 226  /// <summary>
 227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.
 228  /// </summary>
 229  public enum FileUpdateMode
 230  {
 231    /// <summary>
 232    /// Perform all updates on temporary files ensuring that the original file is saved.
 233    /// </summary>
 234    Safe,
 235    /// <summary>
 236    /// Update the archive directly, which is faster but less safe.
 237    /// </summary>
 238    Direct,
 239  }
 240  #endregion
 241
 242  #region ZipFile Class
 243  /// <summary>
 244  /// This class represents a Zip archive.  You can ask for the contained
 245  /// entries, or get an input stream for a file entry.  The entry is
 246  /// automatically decompressed.
 247  ///
 248  /// You can also update the archive adding or deleting entries.
 249  ///
 250  /// This class is thread safe for input:  You can open input streams for arbitrary
 251  /// entries in different threads.
 252  /// <br/>
 253  /// <br/>Author of the original java version : Jochen Hoenicke
 254  /// </summary>
 255  /// <example>
 256  /// <code>
 257  /// using System;
 258  /// using System.Text;
 259  /// using System.Collections;
 260  /// using System.IO;
 261  ///
 262  /// using ICSharpCode.SharpZipLib.Zip;
 263  ///
 264  /// class MainClass
 265  /// {
 266  ///   static public void Main(string[] args)
 267  ///   {
 268  ///     using (ZipFile zFile = new ZipFile(args[0])) {
 269  ///       Console.WriteLine("Listing of : " + zFile.Name);
 270  ///       Console.WriteLine("");
 271  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");
 272  ///       Console.WriteLine("--------  --------  --------  ------  ---------");
 273  ///       foreach (ZipEntry e in zFile) {
 274  ///         if ( e.IsFile ) {
 275  ///           DateTime d = e.DateTime;
 276  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,
 277  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),
 278  ///             e.Name);
 279  ///         }
 280  ///       }
 281  ///     }
 282  ///   }
 283  /// }
 284  /// </code>
 285  /// </example>
 286  public class ZipFile : IEnumerable, IDisposable
 287  {
 288    #region KeyHandling
 289
 290    /// <summary>
 291    /// Delegate for handling keys/password setting during compresion/decompression.
 292    /// </summary>
 293    public delegate void KeysRequiredEventHandler(
 294      object sender,
 295      KeysRequiredEventArgs e
 296    );
 297
 298    /// <summary>
 299    /// Event handler for handling encryption keys.
 300    /// </summary>
 301    public KeysRequiredEventHandler KeysRequired;
 302
 303    /// <summary>
 304    /// Handles getting of encryption keys when required.
 305    /// </summary>
 306    /// <param name="fileName">The file for which encryption keys are required.</param>
 307    void OnKeysRequired(string fileName)
 308    {
 309      if (KeysRequired != null) {
 310        var krea = new KeysRequiredEventArgs(fileName, key);
 311        KeysRequired(this, krea);
 312        key = krea.Key;
 313      }
 314    }
 315
 316    /// <summary>
 317    /// Get/set the encryption key value.
 318    /// </summary>
 319    byte[] Key {
 320      get { return key; }
 321      set { key = value; }
 322    }
 323
 324    /// <summary>
 325    /// Password to be used for encrypting/decrypting files.
 326    /// </summary>
 327    /// <remarks>Set to null if no password is required.</remarks>
 328    public string Password {
 329      set {
 330        if (string.IsNullOrEmpty(value)) {
 331          key = null;
 332        } else {
 333          rawPassword_ = value;
 334          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));
 335        }
 336      }
 337    }
 338
 339    /// <summary>
 340    /// Get a value indicating wether encryption keys are currently available.
 341    /// </summary>
 342    bool HaveKeys {
 343      get { return key != null; }
 344    }
 345    #endregion
 346
 347    #region Constructors
 348    /// <summary>
 349    /// Opens a Zip file with the given name for reading.
 350    /// </summary>
 351    /// <param name="name">The name of the file to open.</param>
 352    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>
 353    /// <exception cref="IOException">
 354    /// An i/o error occurs
 355    /// </exception>
 356    /// <exception cref="ZipException">
 357    /// The file doesn't contain a valid zip archive.
 358    /// </exception>
 359    public ZipFile(string name)
 360    {
 361      if (name == null) {
 362        throw new ArgumentNullException(nameof(name));
 363      }
 364
 365      name_ = name;
 366
 367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 368      isStreamOwner = true;
 369
 370      try {
 371        ReadEntries();
 372      } catch {
 373        DisposeInternal(true);
 374        throw;
 375      }
 376    }
 377
 378    /// <summary>
 379    /// Opens a Zip file reading the given <see cref="FileStream"/>.
 380    /// </summary>
 381    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>
 382    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>
 383    /// <exception cref="IOException">
 384    /// An i/o error occurs.
 385    /// </exception>
 386    /// <exception cref="ZipException">
 387    /// The file doesn't contain a valid zip archive.
 388    /// </exception>
 389    public ZipFile(FileStream file)
 390    {
 391      if (file == null) {
 392        throw new ArgumentNullException(nameof(file));
 393      }
 394
 395      if (!file.CanSeek) {
 396        throw new ArgumentException("Stream is not seekable", nameof(file));
 397      }
 398
 399      baseStream_ = file;
 400      name_ = file.Name;
 401      isStreamOwner = true;
 402
 403      try {
 404        ReadEntries();
 405      } catch {
 406        DisposeInternal(true);
 407        throw;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Opens a Zip file reading the given <see cref="Stream"/>.
 413    /// </summary>
 414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
 415    /// <exception cref="IOException">
 416    /// An i/o error occurs
 417    /// </exception>
 418    /// <exception cref="ZipException">
 419    /// The stream doesn't contain a valid zip archive.<br/>
 420    /// </exception>
 421    /// <exception cref="ArgumentException">
 422    /// The <see cref="Stream">stream</see> doesnt support seeking.
 423    /// </exception>
 424    /// <exception cref="ArgumentNullException">
 425    /// The <see cref="Stream">stream</see> argument is null.
 426    /// </exception>
 427    public ZipFile(Stream stream)
 428    {
 429      if (stream == null) {
 430        throw new ArgumentNullException(nameof(stream));
 431      }
 432
 433      if (!stream.CanSeek) {
 434        throw new ArgumentException("Stream is not seekable", nameof(stream));
 435      }
 436
 437      baseStream_ = stream;
 438      isStreamOwner = true;
 439
 440      if (baseStream_.Length > 0) {
 441        try {
 442          ReadEntries();
 443        } catch {
 444          DisposeInternal(true);
 445          throw;
 446        }
 447      } else {
 448        entries_ = new ZipEntry[0];
 449        isNewArchive_ = true;
 450      }
 451    }
 452
 453    /// <summary>
 454    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
 455    /// </summary>
 456    internal ZipFile()
 457    {
 458      entries_ = new ZipEntry[0];
 459      isNewArchive_ = true;
 460    }
 461
 462    #endregion
 463
 464    #region Destructors and Closing
 465    /// <summary>
 466    /// Finalize this instance.
 467    /// </summary>
 468    ~ZipFile()
 469    {
 470      Dispose(false);
 471    }
 472
 473    /// <summary>
 474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying
 475    /// Once closed, no further instance methods should be called.
 476    /// </summary>
 477    /// <exception cref="System.IO.IOException">
 478    /// An i/o error occurs.
 479    /// </exception>
 480    public void Close()
 481    {
 482      DisposeInternal(true);
 483      GC.SuppressFinalize(this);
 484    }
 485
 486    #endregion
 487
 488    #region Creators
 489    /// <summary>
 490    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.
 491    /// </summary>
 492    /// <param name="fileName">The name of the archive to create.</param>
 493    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 494    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>
 495    public static ZipFile Create(string fileName)
 496    {
 497      if (fileName == null) {
 498        throw new ArgumentNullException(nameof(fileName));
 499      }
 500
 501      FileStream fs = File.Create(fileName);
 502
 503      var result = new ZipFile();
 504      result.name_ = fileName;
 505      result.baseStream_ = fs;
 506      result.isStreamOwner = true;
 507      return result;
 508    }
 509
 510    /// <summary>
 511    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.
 512    /// </summary>
 513    /// <param name="outStream">The stream providing data storage.</param>
 514    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 515    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>
 516    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>
 517    public static ZipFile Create(Stream outStream)
 518    {
 519      if (outStream == null) {
 520        throw new ArgumentNullException(nameof(outStream));
 521      }
 522
 523      if (!outStream.CanWrite) {
 524        throw new ArgumentException("Stream is not writeable", nameof(outStream));
 525      }
 526
 527      if (!outStream.CanSeek) {
 528        throw new ArgumentException("Stream is not seekable", nameof(outStream));
 529      }
 530
 531      var result = new ZipFile();
 532      result.baseStream_ = outStream;
 533      return result;
 534    }
 535
 536    #endregion
 537
 538    #region Properties
 539    /// <summary>
 540    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
 541    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
 542    /// </summary>
 543    /// <remarks>
 544    /// The default value is true in all cases.
 545    /// </remarks>
 546    public bool IsStreamOwner {
 547      get { return isStreamOwner; }
 548      set { isStreamOwner = value; }
 549    }
 550
 551    /// <summary>
 552    /// Get a value indicating wether
 553    /// this archive is embedded in another file or not.
 554    /// </summary>
 555    public bool IsEmbeddedArchive {
 556      // Not strictly correct in all circumstances currently
 557      get { return offsetOfFirstEntry > 0; }
 558    }
 559
 560    /// <summary>
 561    /// Get a value indicating that this archive is a new one.
 562    /// </summary>
 563    public bool IsNewArchive {
 564      get { return isNewArchive_; }
 565    }
 566
 567    /// <summary>
 568    /// Gets the comment for the zip file.
 569    /// </summary>
 570    public string ZipFileComment {
 571      get { return comment_; }
 572    }
 573
 574    /// <summary>
 575    /// Gets the name of this zip file.
 576    /// </summary>
 577    public string Name {
 578      get { return name_; }
 579    }
 580
 581    /// <summary>
 582    /// Gets the number of entries in this zip file.
 583    /// </summary>
 584    /// <exception cref="InvalidOperationException">
 585    /// The Zip file has been closed.
 586    /// </exception>
 587    [Obsolete("Use the Count property instead")]
 588    public int Size {
 589      get {
 590        return entries_.Length;
 591      }
 592    }
 593
 594    /// <summary>
 595    /// Get the number of entries contained in this <see cref="ZipFile"/>.
 596    /// </summary>
 597    public long Count {
 598      get {
 599        return entries_.Length;
 600      }
 601    }
 602
 603    /// <summary>
 604    /// Indexer property for ZipEntries
 605    /// </summary>
 606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
 607    public ZipEntry this[int index] {
 608      get {
 609        return (ZipEntry)entries_[index].Clone();
 610      }
 611    }
 612
 613    #endregion
 614
 615    #region Input Handling
 616    /// <summary>
 617    /// Gets an enumerator for the Zip entries in this Zip file.
 618    /// </summary>
 619    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>
 620    /// <exception cref="ObjectDisposedException">
 621    /// The Zip file has been closed.
 622    /// </exception>
 623    public IEnumerator GetEnumerator()
 624    {
 625      if (isDisposed_) {
 626        throw new ObjectDisposedException("ZipFile");
 627      }
 628
 629      return new ZipEntryEnumerator(entries_);
 630    }
 631
 632    /// <summary>
 633    /// Return the index of the entry with a matching name
 634    /// </summary>
 635    /// <param name="name">Entry name to find</param>
 636    /// <param name="ignoreCase">If true the comparison is case insensitive</param>
 637    /// <returns>The index position of the matching entry or -1 if not found</returns>
 638    /// <exception cref="ObjectDisposedException">
 639    /// The Zip file has been closed.
 640    /// </exception>
 641    public int FindEntry(string name, bool ignoreCase)
 642    {
 643      if (isDisposed_) {
 644        throw new ObjectDisposedException("ZipFile");
 645      }
 646
 647      // TODO: This will be slow as the next ice age for huge archives!
 648      for (int i = 0; i < entries_.Length; i++) {
 649        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {
 650          return i;
 651        }
 652      }
 653      return -1;
 654    }
 655
 656    /// <summary>
 657    /// Searches for a zip entry in this archive with the given name.
 658    /// String comparisons are case insensitive
 659    /// </summary>
 660    /// <param name="name">
 661    /// The name to find. May contain directory components separated by slashes ('/').
 662    /// </param>
 663    /// <returns>
 664    /// A clone of the zip entry, or null if no entry with that name exists.
 665    /// </returns>
 666    /// <exception cref="ObjectDisposedException">
 667    /// The Zip file has been closed.
 668    /// </exception>
 669    public ZipEntry GetEntry(string name)
 670    {
 671      if (isDisposed_) {
 672        throw new ObjectDisposedException("ZipFile");
 673      }
 674
 675      int index = FindEntry(name, true);
 676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;
 677    }
 678
 679    /// <summary>
 680    /// Gets an input stream for reading the given zip entry data in an uncompressed form.
 681    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
 682    /// </summary>
 683    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
 684    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
 685    /// <exception cref="ObjectDisposedException">
 686    /// The ZipFile has already been closed
 687    /// </exception>
 688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 689    /// The compression method for the entry is unknown
 690    /// </exception>
 691    /// <exception cref="IndexOutOfRangeException">
 692    /// The entry is not found in the ZipFile
 693    /// </exception>
 694    public Stream GetInputStream(ZipEntry entry)
 695    {
 696      if (entry == null) {
 697        throw new ArgumentNullException(nameof(entry));
 698      }
 699
 700      if (isDisposed_) {
 701        throw new ObjectDisposedException("ZipFile");
 702      }
 703
 704      long index = entry.ZipFileIndex;
 705      if ((index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name)) {
 706        index = FindEntry(entry.Name, true);
 707        if (index < 0) {
 708          throw new ZipException("Entry cannot be found");
 709        }
 710      }
 711      return GetInputStream(index);
 712    }
 713
 714    /// <summary>
 715    /// Creates an input stream reading a zip entry
 716    /// </summary>
 717    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
 718    /// <returns>
 719    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>
 720    /// </returns>
 721    /// <exception cref="ObjectDisposedException">
 722    /// The ZipFile has already been closed
 723    /// </exception>
 724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 725    /// The compression method for the entry is unknown
 726    /// </exception>
 727    /// <exception cref="IndexOutOfRangeException">
 728    /// The entry is not found in the ZipFile
 729    /// </exception>
 730    public Stream GetInputStream(long entryIndex)
 731    {
 732      if (isDisposed_) {
 733        throw new ObjectDisposedException("ZipFile");
 734      }
 735
 736      long start = LocateEntry(entries_[entryIndex]);
 737      CompressionMethod method = entries_[entryIndex].CompressionMethod;
 738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);
 739
 740      if (entries_[entryIndex].IsCrypted == true) {
 741        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);
 742        if (result == null) {
 743          throw new ZipException("Unable to decrypt this entry");
 744        }
 745      }
 746
 747      switch (method) {
 748        case CompressionMethod.Stored:
 749          // read as is.
 750          break;
 751
 752        case CompressionMethod.Deflated:
 753          // No need to worry about ownership and closing as underlying stream close does nothing.
 754          result = new InflaterInputStream(result, new Inflater(true));
 755          break;
 756
 757        default:
 758          throw new ZipException("Unsupported compression method " + method);
 759      }
 760
 761      return result;
 762    }
 763
 764    #endregion
 765
 766    #region Archive Testing
 767    /// <summary>
 768    /// Test an archive for integrity/validity
 769    /// </summary>
 770    /// <param name="testData">Perform low level data Crc check</param>
 771    /// <returns>true if all tests pass, false otherwise</returns>
 772    /// <remarks>Testing will terminate on the first error found.</remarks>
 773    public bool TestArchive(bool testData)
 774    {
 775      return TestArchive(testData, TestStrategy.FindFirstError, null);
 776    }
 777
 778    /// <summary>
 779    /// Test an archive for integrity/validity
 780    /// </summary>
 781    /// <param name="testData">Perform low level data Crc check</param>
 782    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
 783    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
 784    /// <returns>true if all tests pass, false otherwise</returns>
 785    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>
 786    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
 787    {
 788      if (isDisposed_) {
 789        throw new ObjectDisposedException("ZipFile");
 790      }
 791
 792      var status = new TestStatus(this);
 793
 794      if (resultHandler != null) {
 795        resultHandler(status, null);
 796      }
 797
 798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;
 799
 800      bool testing = true;
 801
 802      try {
 803        int entryIndex = 0;
 804
 805        while (testing && (entryIndex < Count)) {
 806          if (resultHandler != null) {
 807            status.SetEntry(this[entryIndex]);
 808            status.SetOperation(TestOperation.EntryHeader);
 809            resultHandler(status, null);
 810          }
 811
 812          try {
 813            TestLocalHeader(this[entryIndex], test);
 814          } catch (ZipException ex) {
 815            status.AddError();
 816
 817            if (resultHandler != null) {
 818              resultHandler(status,
 819                string.Format("Exception during test - '{0}'", ex.Message));
 820            }
 821
 822            testing &= strategy != TestStrategy.FindFirstError;
 823          }
 824
 825          if (testing && testData && this[entryIndex].IsFile) {
 826            if (resultHandler != null) {
 827              status.SetOperation(TestOperation.EntryData);
 828              resultHandler(status, null);
 829            }
 830
 831            var crc = new Crc32();
 832
 833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {
 834
 835              byte[] buffer = new byte[4096];
 836              long totalBytes = 0;
 837              int bytesRead;
 838              while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
 839                crc.Update(buffer, 0, bytesRead);
 840
 841                if (resultHandler != null) {
 842                  totalBytes += bytesRead;
 843                  status.SetBytesTested(totalBytes);
 844                  resultHandler(status, null);
 845                }
 846              }
 847            }
 848
 849            if (this[entryIndex].Crc != crc.Value) {
 850              status.AddError();
 851
 852              if (resultHandler != null) {
 853                resultHandler(status, "CRC mismatch");
 854              }
 855
 856              testing &= strategy != TestStrategy.FindFirstError;
 857            }
 858
 859            if ((this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 860              var helper = new ZipHelperStream(baseStream_);
 861              var data = new DescriptorData();
 862              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
 863              if (this[entryIndex].Crc != data.Crc) {
 864                status.AddError();
 865              }
 866
 867              if (this[entryIndex].CompressedSize != data.CompressedSize) {
 868                status.AddError();
 869              }
 870
 871              if (this[entryIndex].Size != data.Size) {
 872                status.AddError();
 873              }
 874            }
 875          }
 876
 877          if (resultHandler != null) {
 878            status.SetOperation(TestOperation.EntryComplete);
 879            resultHandler(status, null);
 880          }
 881
 882          entryIndex += 1;
 883        }
 884
 885        if (resultHandler != null) {
 886          status.SetOperation(TestOperation.MiscellaneousTests);
 887          resultHandler(status, null);
 888        }
 889
 890        // TODO: the 'Corrina Johns' test where local headers are missing from
 891        // the central directory.  They are therefore invisible to many archivers.
 892      } catch (Exception ex) {
 893        status.AddError();
 894
 895        if (resultHandler != null) {
 896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
 897        }
 898      }
 899
 900      if (resultHandler != null) {
 901        status.SetOperation(TestOperation.Complete);
 902        status.SetEntry(null);
 903        resultHandler(status, null);
 904      }
 905
 906      return (status.ErrorCount == 0);
 907    }
 908
 909    [Flags]
 910    enum HeaderTest
 911    {
 912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted
 913      Header = 0x02,     // Check that this header contents are valid
 914    }
 915
 916    /// <summary>
 917    /// Test a local header against that provided from the central directory
 918    /// </summary>
 919    /// <param name="entry">
 920    /// The entry to test against
 921    /// </param>
 922    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
 923    /// <returns>The offset of the entries data in the file</returns>
 924    long TestLocalHeader(ZipEntry entry, HeaderTest tests)
 925    {
 926      lock (baseStream_) {
 927        bool testHeader = (tests & HeaderTest.Header) != 0;
 928        bool testData = (tests & HeaderTest.Extract) != 0;
 929
 930        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
 931        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
 932          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)
 933        }
 934
 935        var extractVersion = (short)(ReadLEUshort() & 0x00ff);
 936        var localFlags = (short)ReadLEUshort();
 937        var compressionMethod = (short)ReadLEUshort();
 938        var fileTime = (short)ReadLEUshort();
 939        var fileDate = (short)ReadLEUshort();
 940        uint crcValue = ReadLEUint();
 941        long compressedSize = ReadLEUint();
 942        long size = ReadLEUint();
 943        int storedNameLength = ReadLEUshort();
 944        int extraDataLength = ReadLEUshort();
 945
 946        byte[] nameData = new byte[storedNameLength];
 947        StreamUtils.ReadFully(baseStream_, nameData);
 948
 949        byte[] extraData = new byte[extraDataLength];
 950        StreamUtils.ReadFully(baseStream_, extraData);
 951
 952        var localExtraData = new ZipExtraData(extraData);
 953
 954        // Extra data / zip64 checks
 955        if (localExtraData.Find(1)) {
 956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
 957          // and size or compressedSize = MaxValue, due to rogue creators.
 958
 959          size = localExtraData.ReadLong();
 960          compressedSize = localExtraData.ReadLong();
 961
 962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {
 963            // These may be valid if patched later
 964            if ((size != -1) && (size != entry.Size)) {
 965              throw new ZipException("Size invalid for descriptor");
 966            }
 967
 968            if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {
 969              throw new ZipException("Compressed size invalid for descriptor");
 970            }
 971          }
 972        } else {
 973          // No zip64 extra data but entry requires it.
 974          if ((extractVersion >= ZipConstants.VersionZip64) &&
 975            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) {
 976            throw new ZipException("Required Zip64 extended information missing");
 977          }
 978        }
 979
 980        if (testData) {
 981          if (entry.IsFile) {
 982            if (!entry.IsCompressionMethodSupported()) {
 983              throw new ZipException("Compression method not supported");
 984            }
 985
 986            if ((extractVersion > ZipConstants.VersionMadeBy)
 987              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64))) {
 988              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract
 989            }
 990
 991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance
 992              throw new ZipException("The library does not support the zip version required to extract this entry");
 993            }
 994          }
 995        }
 996
 997        if (testHeader) {
 998          if ((extractVersion <= 63) &&   // Ignore later versions as we dont know about them..
 999            (extractVersion != 10) &&
 1000            (extractVersion != 11) &&
 1001            (extractVersion != 20) &&
 1002            (extractVersion != 21) &&
 1003            (extractVersion != 25) &&
 1004            (extractVersion != 27) &&
 1005            (extractVersion != 45) &&
 1006            (extractVersion != 46) &&
 1007            (extractVersion != 50) &&
 1008            (extractVersion != 51) &&
 1009            (extractVersion != 52) &&
 1010            (extractVersion != 61) &&
 1011            (extractVersion != 62) &&
 1012            (extractVersion != 63)
 1013            ) {
 1014            throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersi
 1015          }
 1016
 1017          // Local entry flags dont have reserved bit set on.
 1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R
 1019            throw new ZipException("Reserved bit flags cannot be set.");
 1020          }
 1021
 1022          // Encryption requires extract version >= 20
 1023          if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) {
 1024            throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})
 1025          }
 1026
 1027          // Strong encryption requires encryption flag to be set and extract version >= 50.
 1028          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1029            if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) {
 1030              throw new ZipException("Strong encryption flag set but encryption flag is not set");
 1031            }
 1032
 1033            if (extractVersion < 50) {
 1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0
 1035            }
 1036          }
 1037
 1038          // Patched entries require extract version >= 27
 1039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {
 1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
 1041          }
 1042
 1043          // Central header flags match local entry flags.
 1044          if (localFlags != entry.Flags) {
 1045            throw new ZipException("Central header/local header flags mismatch");
 1046          }
 1047
 1048          // Central header compression method matches local entry
 1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {
 1050            throw new ZipException("Central header/local header compression method mismatch");
 1051          }
 1052
 1053          if (entry.Version != extractVersion) {
 1054            throw new ZipException("Extract version mismatch");
 1055          }
 1056
 1057          // Strong encryption and extract version match
 1058          if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 1059            if (extractVersion < 62) {
 1060              throw new ZipException("Strong encryption flag set but version not high enough");
 1061            }
 1062          }
 1063
 1064          if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) {
 1065            if ((fileTime != 0) || (fileDate != 0)) {
 1066              throw new ZipException("Header masked set but date/time values non-zero");
 1067            }
 1068          }
 1069
 1070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
 1071            if (crcValue != (uint)entry.Crc) {
 1072              throw new ZipException("Central header/local header crc mismatch");
 1073            }
 1074          }
 1075
 1076          // Crc valid for empty entry.
 1077          // This will also apply to streamed entries where size isnt known and the header cant be patched
 1078          if ((size == 0) && (compressedSize == 0)) {
 1079            if (crcValue != 0) {
 1080              throw new ZipException("Invalid CRC for empty entry");
 1081            }
 1082          }
 1083
 1084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str
 1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
 1086          if (entry.Name.Length > storedNameLength) {
 1087            throw new ZipException("File name length mismatch");
 1088          }
 1089
 1090          // Name data has already been read convert it and compare.
 1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);
 1092
 1093          // Central directory and local entry name match
 1094          if (localName != entry.Name) {
 1095            throw new ZipException("Central header and local header file name mismatch");
 1096          }
 1097
 1098          // Directories have zero actual size but can have compressed size
 1099          if (entry.IsDirectory) {
 1100            if (size > 0) {
 1101              throw new ZipException("Directory cannot have size");
 1102            }
 1103
 1104            // There may be other cases where the compressed size can be greater than this?
 1105            // If so until details are known we will be strict.
 1106            if (entry.IsCrypted) {
 1107              if (compressedSize > ZipConstants.CryptoHeaderSize + 2) {
 1108                throw new ZipException("Directory compressed size invalid");
 1109              }
 1110            } else if (compressedSize > 2) {
 1111              // When not compressed the directory size can validly be 2 bytes
 1112              // if the true size wasnt known when data was originally being written.
 1113              // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
 1114              throw new ZipException("Directory compressed size invalid");
 1115            }
 1116          }
 1117
 1118          if (!ZipNameTransform.IsValidName(localName, true)) {
 1119            throw new ZipException("Name is invalid");
 1120          }
 1121        }
 1122
 1123        // Tests that apply to both data and header.
 1124
 1125        // Size can be verified only if it is known in the local header.
 1126        // it will always be known in the central header.
 1127        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
 1128          ((size > 0 || compressedSize > 0) && entry.Size > 0)) {
 1129
 1130          if ((size != 0)
 1131            && (size != entry.Size)) {
 1132            throw new ZipException(
 1133              string.Format("Size mismatch between central header({0}) and local header({1})",
 1134                entry.Size, size));
 1135          }
 1136
 1137          if ((compressedSize != 0)
 1138            && (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) {
 1139            throw new ZipException(
 1140              string.Format("Compressed size mismatch between central header({0}) and local header({1})",
 1141              entry.CompressedSize, compressedSize));
 1142          }
 1143        }
 1144
 1145        int extraLength = storedNameLength + extraDataLength;
 1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
 1147      }
 1148    }
 1149
 1150    #endregion
 1151
 1152    #region Updating
 1153
 1154    const int DefaultBufferSize = 4096;
 1155
 1156    /// <summary>
 1157    /// The kind of update to apply.
 1158    /// </summary>
 1159    enum UpdateCommand
 1160    {
 1161      Copy,       // Copy original file contents.
 1162      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.
 1163      Add,        // Add a new file to the archive.
 1164    }
 1165
 1166    #region Properties
 1167    /// <summary>
 1168    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.
 1169    /// </summary>
 1170    public INameTransform NameTransform {
 1171      get {
 1172        return updateEntryFactory_.NameTransform;
 1173      }
 1174
 1175      set {
 1176        updateEntryFactory_.NameTransform = value;
 1177      }
 1178    }
 1179
 1180    /// <summary>
 1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values
 1182    /// during updates.
 1183    /// </summary>
 1184    public IEntryFactory EntryFactory {
 1185      get {
 1186        return updateEntryFactory_;
 1187      }
 1188
 1189      set {
 1190        if (value == null) {
 1191          updateEntryFactory_ = new ZipEntryFactory();
 1192        } else {
 1193          updateEntryFactory_ = value;
 1194        }
 1195      }
 1196    }
 1197
 1198    /// <summary>
 1199    /// Get /set the buffer size to be used when updating this zip file.
 1200    /// </summary>
 1201    public int BufferSize {
 1202      get { return bufferSize_; }
 1203      set {
 1204        if (value < 1024) {
 1205          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");
 1206        }
 1207
 1208        if (bufferSize_ != value) {
 1209          bufferSize_ = value;
 1210          copyBuffer_ = null;
 1211        }
 1212      }
 1213    }
 1214
 1215    /// <summary>
 1216    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.
 1217    /// </summary>
 1218    public bool IsUpdating {
 1219      get { return updates_ != null; }
 1220    }
 1221
 1222    /// <summary>
 1223    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
 1224    /// </summary>
 1225    public UseZip64 UseZip64 {
 1226      get { return useZip64_; }
 1227      set { useZip64_ = value; }
 1228    }
 1229
 1230    #endregion
 1231
 1232    #region Immediate updating
 1233    //    TBD: Direct form of updating
 1234    //
 1235    //    public void Update(IEntryMatcher deleteMatcher)
 1236    //    {
 1237    //    }
 1238    //
 1239    //    public void Update(IScanner addScanner)
 1240    //    {
 1241    //    }
 1242    #endregion
 1243
 1244    #region Deferred Updating
 1245    /// <summary>
 1246    /// Begin updating this <see cref="ZipFile"/> archive.
 1247    /// </summary>
 1248    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p
 1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param
 1250    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1251    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>
 1252    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1253    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)
 1254    {
 1255      if (archiveStorage == null) {
 1256        throw new ArgumentNullException(nameof(archiveStorage));
 1257      }
 1258
 1259      if (dataSource == null) {
 1260        throw new ArgumentNullException(nameof(dataSource));
 1261      }
 1262
 1263      if (isDisposed_) {
 1264        throw new ObjectDisposedException("ZipFile");
 1265      }
 1266
 1267      if (IsEmbeddedArchive) {
 1268        throw new ZipException("Cannot update embedded/SFX archives");
 1269      }
 1270
 1271      archiveStorage_ = archiveStorage;
 1272      updateDataSource_ = dataSource;
 1273
 1274      // NOTE: the baseStream_ may not currently support writing or seeking.
 1275
 1276      updateIndex_ = new Hashtable();
 1277
 1278      updates_ = new ArrayList(entries_.Length);
 1279      foreach (ZipEntry entry in entries_) {
 1280        int index = updates_.Add(new ZipUpdate(entry));
 1281        updateIndex_.Add(entry.Name, index);
 1282      }
 1283
 1284      // We must sort by offset before using offset's calculated sizes
 1285      updates_.Sort(new UpdateComparer());
 1286
 1287      int idx = 0;
 1288      foreach (ZipUpdate update in updates_) {
 1289        //If last entry, there is no next entry offset to use
 1290        if (idx == updates_.Count - 1)
 1291          break;
 1292
 1293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;
 1294        idx++;
 1295      }
 1296      updateCount_ = updates_.Count;
 1297
 1298      contentsEdited_ = false;
 1299      commentEdited_ = false;
 1300      newComment_ = null;
 1301    }
 1302
 1303    /// <summary>
 1304    /// Begin updating to this <see cref="ZipFile"/> archive.
 1305    /// </summary>
 1306    /// <param name="archiveStorage">The storage to use during the update.</param>
 1307    public void BeginUpdate(IArchiveStorage archiveStorage)
 1308    {
 1309      BeginUpdate(archiveStorage, new DynamicDiskDataSource());
 1310    }
 1311
 1312    /// <summary>
 1313    /// Begin updating this <see cref="ZipFile"/> archive.
 1314    /// </summary>
 1315    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>
 1316    /// <seealso cref="CommitUpdate"></seealso>
 1317    /// <seealso cref="AbortUpdate"></seealso>
 1318    public void BeginUpdate()
 1319    {
 1320      if (Name == null) {
 1321        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());
 1322      } else {
 1323        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());
 1324      }
 1325    }
 1326
 1327    /// <summary>
 1328    /// Commit current updates, updating this archive.
 1329    /// </summary>
 1330    /// <seealso cref="BeginUpdate()"></seealso>
 1331    /// <seealso cref="AbortUpdate"></seealso>
 1332    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1333    public void CommitUpdate()
 1334    {
 1335      if (isDisposed_) {
 1336        throw new ObjectDisposedException("ZipFile");
 1337      }
 1338
 1339      CheckUpdating();
 1340
 1341      try {
 1342        updateIndex_.Clear();
 1343        updateIndex_ = null;
 1344
 1345        if (contentsEdited_) {
 1346          RunUpdates();
 1347        } else if (commentEdited_) {
 1348          UpdateCommentOnly();
 1349        } else {
 1350          // Create an empty archive if none existed originally.
 1351          if (entries_.Length == 0) {
 1352            byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 1353            using (ZipHelperStream zhs = new ZipHelperStream(baseStream_)) {
 1354              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
 1355            }
 1356          }
 1357        }
 1358
 1359      } finally {
 1360        PostUpdateCleanup();
 1361      }
 1362    }
 1363
 1364    /// <summary>
 1365    /// Abort updating leaving the archive unchanged.
 1366    /// </summary>
 1367    /// <seealso cref="BeginUpdate()"></seealso>
 1368    /// <seealso cref="CommitUpdate"></seealso>
 1369    public void AbortUpdate()
 1370    {
 1371      PostUpdateCleanup();
 1372    }
 1373
 1374    /// <summary>
 1375    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.
 1376    /// </summary>
 1377    /// <param name="comment">The comment to record.</param>
 1378    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1379    public void SetComment(string comment)
 1380    {
 1381      if (isDisposed_) {
 1382        throw new ObjectDisposedException("ZipFile");
 1383      }
 1384
 1385      CheckUpdating();
 1386
 1387      newComment_ = new ZipString(comment);
 1388
 1389      if (newComment_.RawLength > 0xffff) {
 1390        newComment_ = null;
 1391        throw new ZipException("Comment length exceeds maximum - 65535");
 1392      }
 1393
 1394      // We dont take account of the original and current comment appearing to be the same
 1395      // as encoding may be different.
 1396      commentEdited_ = true;
 1397    }
 1398
 1399    #endregion
 1400
 1401    #region Adding Entries
 1402
 1403    void AddUpdate(ZipUpdate update)
 1404    {
 1405      contentsEdited_ = true;
 1406
 1407      int index = FindExistingUpdate(update.Entry.Name);
 1408
 1409      if (index >= 0) {
 1410        if (updates_[index] == null) {
 1411          updateCount_ += 1;
 1412        }
 1413
 1414        // Direct replacement is faster than delete and add.
 1415        updates_[index] = update;
 1416      } else {
 1417        index = updates_.Add(update);
 1418        updateCount_ += 1;
 1419        updateIndex_.Add(update.Entry.Name, index);
 1420      }
 1421    }
 1422
 1423    /// <summary>
 1424    /// Add a new entry to the archive.
 1425    /// </summary>
 1426    /// <param name="fileName">The name of the file to add.</param>
 1427    /// <param name="compressionMethod">The compression method to use.</param>
 1428    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>
 1429    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1430    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1431    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>
 1432    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText)
 1433    {
 1434      if (fileName == null) {
 1435        throw new ArgumentNullException(nameof(fileName));
 1436      }
 1437
 1438      if (isDisposed_) {
 1439        throw new ObjectDisposedException("ZipFile");
 1440      }
 1441
 1442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1444      }
 1445
 1446      CheckUpdating();
 1447      contentsEdited_ = true;
 1448
 1449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1450      entry.IsUnicodeText = useUnicodeText;
 1451      entry.CompressionMethod = compressionMethod;
 1452
 1453      AddUpdate(new ZipUpdate(fileName, entry));
 1454    }
 1455
 1456    /// <summary>
 1457    /// Add a new entry to the archive.
 1458    /// </summary>
 1459    /// <param name="fileName">The name of the file to add.</param>
 1460    /// <param name="compressionMethod">The compression method to use.</param>
 1461    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>
 1462    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>
 1463    public void Add(string fileName, CompressionMethod compressionMethod)
 1464    {
 1465      if (fileName == null) {
 1466        throw new ArgumentNullException(nameof(fileName));
 1467      }
 1468
 1469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1471      }
 1472
 1473      CheckUpdating();
 1474      contentsEdited_ = true;
 1475
 1476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 1477      entry.CompressionMethod = compressionMethod;
 1478      AddUpdate(new ZipUpdate(fileName, entry));
 1479    }
 1480
 1481    /// <summary>
 1482    /// Add a file to the archive.
 1483    /// </summary>
 1484    /// <param name="fileName">The name of the file to add.</param>
 1485    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1486    public void Add(string fileName)
 1487    {
 1488      if (fileName == null) {
 1489        throw new ArgumentNullException(nameof(fileName));
 1490      }
 1491
 1492      CheckUpdating();
 1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));
 1494    }
 1495
 1496    /// <summary>
 1497    /// Add a file to the archive.
 1498    /// </summary>
 1499    /// <param name="fileName">The name of the file to add.</param>
 1500    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>
 1501    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1502    public void Add(string fileName, string entryName)
 1503    {
 1504      if (fileName == null) {
 1505        throw new ArgumentNullException(nameof(fileName));
 1506      }
 1507
 1508      if (entryName == null) {
 1509        throw new ArgumentNullException(nameof(entryName));
 1510      }
 1511
 1512      CheckUpdating();
 1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));
 1514    }
 1515
 1516
 1517    /// <summary>
 1518    /// Add a file entry with data.
 1519    /// </summary>
 1520    /// <param name="dataSource">The source of the data for this entry.</param>
 1521    /// <param name="entryName">The name to give to the entry.</param>
 1522    public void Add(IStaticDataSource dataSource, string entryName)
 1523    {
 1524      if (dataSource == null) {
 1525        throw new ArgumentNullException(nameof(dataSource));
 1526      }
 1527
 1528      if (entryName == null) {
 1529        throw new ArgumentNullException(nameof(entryName));
 1530      }
 1531
 1532      CheckUpdating();
 1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));
 1534    }
 1535
 1536    /// <summary>
 1537    /// Add a file entry with data.
 1538    /// </summary>
 1539    /// <param name="dataSource">The source of the data for this entry.</param>
 1540    /// <param name="entryName">The name to give to the entry.</param>
 1541    /// <param name="compressionMethod">The compression method to use.</param>
 1542    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 1543    {
 1544      if (dataSource == null) {
 1545        throw new ArgumentNullException(nameof(dataSource));
 1546      }
 1547
 1548      if (entryName == null) {
 1549        throw new ArgumentNullException(nameof(entryName));
 1550      }
 1551
 1552      CheckUpdating();
 1553
 1554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1555      entry.CompressionMethod = compressionMethod;
 1556
 1557      AddUpdate(new ZipUpdate(dataSource, entry));
 1558    }
 1559
 1560    /// <summary>
 1561    /// Add a file entry with data.
 1562    /// </summary>
 1563    /// <param name="dataSource">The source of the data for this entry.</param>
 1564    /// <param name="entryName">The name to give to the entry.</param>
 1565    /// <param name="compressionMethod">The compression method to use.</param>
 1566    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>
 1567    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode
 1568    {
 1569      if (dataSource == null) {
 1570        throw new ArgumentNullException(nameof(dataSource));
 1571      }
 1572
 1573      if (entryName == null) {
 1574        throw new ArgumentNullException(nameof(entryName));
 1575      }
 1576
 1577      CheckUpdating();
 1578
 1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 1580      entry.IsUnicodeText = useUnicodeText;
 1581      entry.CompressionMethod = compressionMethod;
 1582
 1583      AddUpdate(new ZipUpdate(dataSource, entry));
 1584    }
 1585
 1586    /// <summary>
 1587    /// Add a <see cref="ZipEntry"/> that contains no data.
 1588    /// </summary>
 1589    /// <param name="entry">The entry to add.</param>
 1590    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
 1591    public void Add(ZipEntry entry)
 1592    {
 1593      if (entry == null) {
 1594        throw new ArgumentNullException(nameof(entry));
 1595      }
 1596
 1597      CheckUpdating();
 1598
 1599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {
 1600        throw new ZipException("Entry cannot have any data");
 1601      }
 1602
 1603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
 1604    }
 1605
 1606    /// <summary>
 1607    /// Add a directory entry to the archive.
 1608    /// </summary>
 1609    /// <param name="directoryName">The directory to add.</param>
 1610    public void AddDirectory(string directoryName)
 1611    {
 1612      if (directoryName == null) {
 1613        throw new ArgumentNullException(nameof(directoryName));
 1614      }
 1615
 1616      CheckUpdating();
 1617
 1618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);
 1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));
 1620    }
 1621
 1622    #endregion
 1623
 1624    #region Modifying Entries
 1625    /* Modify not yet ready for public consumption.
 1626       Direct modification of an entry should not overwrite original data before its read.
 1627       Safe mode is trivial in this sense.
 1628        public void Modify(ZipEntry original, ZipEntry updated)
 1629        {
 1630          if ( original == null ) {
 1631            throw new ArgumentNullException("original");
 1632          }
 1633
 1634          if ( updated == null ) {
 1635            throw new ArgumentNullException("updated");
 1636          }
 1637
 1638          CheckUpdating();
 1639          contentsEdited_ = true;
 1640          updates_.Add(new ZipUpdate(original, updated));
 1641        }
 1642    */
 1643    #endregion
 1644
 1645    #region Deleting Entries
 1646    /// <summary>
 1647    /// Delete an entry by name
 1648    /// </summary>
 1649    /// <param name="fileName">The filename to delete</param>
 1650    /// <returns>True if the entry was found and deleted; false otherwise.</returns>
 1651    public bool Delete(string fileName)
 1652    {
 1653      if (fileName == null) {
 1654        throw new ArgumentNullException(nameof(fileName));
 1655      }
 1656
 1657      CheckUpdating();
 1658
 1659      bool result = false;
 1660      int index = FindExistingUpdate(fileName);
 1661      if ((index >= 0) && (updates_[index] != null)) {
 1662        result = true;
 1663        contentsEdited_ = true;
 1664        updates_[index] = null;
 1665        updateCount_ -= 1;
 1666      } else {
 1667        throw new ZipException("Cannot find entry to delete");
 1668      }
 1669      return result;
 1670    }
 1671
 1672    /// <summary>
 1673    /// Delete a <see cref="ZipEntry"/> from the archive.
 1674    /// </summary>
 1675    /// <param name="entry">The entry to delete.</param>
 1676    public void Delete(ZipEntry entry)
 1677    {
 1678      if (entry == null) {
 1679        throw new ArgumentNullException(nameof(entry));
 1680      }
 1681
 1682      CheckUpdating();
 1683
 1684      int index = FindExistingUpdate(entry);
 1685      if (index >= 0) {
 1686        contentsEdited_ = true;
 1687        updates_[index] = null;
 1688        updateCount_ -= 1;
 1689      } else {
 1690        throw new ZipException("Cannot find entry to delete");
 1691      }
 1692    }
 1693
 1694    #endregion
 1695
 1696    #region Update Support
 1697
 1698    #region Writing Values/Headers
 1699    void WriteLEShort(int value)
 1700    {
 1701      baseStream_.WriteByte((byte)(value & 0xff));
 1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));
 1703    }
 1704
 1705    /// <summary>
 1706    /// Write an unsigned short in little endian byte order.
 1707    /// </summary>
 1708    void WriteLEUshort(ushort value)
 1709    {
 1710      baseStream_.WriteByte((byte)(value & 0xff));
 1711      baseStream_.WriteByte((byte)(value >> 8));
 1712    }
 1713
 1714    /// <summary>
 1715    /// Write an int in little endian byte order.
 1716    /// </summary>
 1717    void WriteLEInt(int value)
 1718    {
 1719      WriteLEShort(value & 0xffff);
 1720      WriteLEShort(value >> 16);
 1721    }
 1722
 1723    /// <summary>
 1724    /// Write an unsigned int in little endian byte order.
 1725    /// </summary>
 1726    void WriteLEUint(uint value)
 1727    {
 1728      WriteLEUshort((ushort)(value & 0xffff));
 1729      WriteLEUshort((ushort)(value >> 16));
 1730    }
 1731
 1732    /// <summary>
 1733    /// Write a long in little endian byte order.
 1734    /// </summary>
 1735    void WriteLeLong(long value)
 1736    {
 1737      WriteLEInt((int)(value & 0xffffffff));
 1738      WriteLEInt((int)(value >> 32));
 1739    }
 1740
 1741    void WriteLEUlong(ulong value)
 1742    {
 1743      WriteLEUint((uint)(value & 0xffffffff));
 1744      WriteLEUint((uint)(value >> 32));
 1745    }
 1746
 1747    void WriteLocalEntryHeader(ZipUpdate update)
 1748    {
 1749      ZipEntry entry = update.OutEntry;
 1750
 1751      // TODO: Local offset will require adjusting for multi-disk zip files.
 1752      entry.Offset = baseStream_.Position;
 1753
 1754      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
 1755      if (update.Command != UpdateCommand.Copy) {
 1756        if (entry.CompressionMethod == CompressionMethod.Deflated) {
 1757          if (entry.Size == 0) {
 1758            // No need to compress - no data.
 1759            entry.CompressedSize = entry.Size;
 1760            entry.Crc = 0;
 1761            entry.CompressionMethod = CompressionMethod.Stored;
 1762          }
 1763        } else if (entry.CompressionMethod == CompressionMethod.Stored) {
 1764          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
 1765        }
 1766
 1767        if (HaveKeys) {
 1768          entry.IsCrypted = true;
 1769          if (entry.Crc < 0) {
 1770            entry.Flags |= (int)GeneralBitFlags.Descriptor;
 1771          }
 1772        } else {
 1773          entry.IsCrypted = false;
 1774        }
 1775
 1776        switch (useZip64_) {
 1777          case UseZip64.Dynamic:
 1778            if (entry.Size < 0) {
 1779              entry.ForceZip64();
 1780            }
 1781            break;
 1782
 1783          case UseZip64.On:
 1784            entry.ForceZip64();
 1785            break;
 1786
 1787          case UseZip64.Off:
 1788            // Do nothing.  The entry itself may be using Zip64 independantly.
 1789            break;
 1790        }
 1791      }
 1792
 1793      // Write the local file header
 1794      WriteLEInt(ZipConstants.LocalHeaderSignature);
 1795
 1796      WriteLEShort(entry.Version);
 1797      WriteLEShort(entry.Flags);
 1798
 1799      WriteLEShort((byte)entry.CompressionMethod);
 1800      WriteLEInt((int)entry.DosTime);
 1801
 1802      if (!entry.HasCrc) {
 1803        // Note patch address for updating CRC later.
 1804        update.CrcPatchOffset = baseStream_.Position;
 1805        WriteLEInt((int)0);
 1806      } else {
 1807        WriteLEInt(unchecked((int)entry.Crc));
 1808      }
 1809
 1810      if (entry.LocalHeaderRequiresZip64) {
 1811        WriteLEInt(-1);
 1812        WriteLEInt(-1);
 1813      } else {
 1814        if ((entry.CompressedSize < 0) || (entry.Size < 0)) {
 1815          update.SizePatchOffset = baseStream_.Position;
 1816        }
 1817
 1818        WriteLEInt((int)entry.CompressedSize);
 1819        WriteLEInt((int)entry.Size);
 1820      }
 1821
 1822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1823
 1824      if (name.Length > 0xFFFF) {
 1825        throw new ZipException("Entry name too long.");
 1826      }
 1827
 1828      var ed = new ZipExtraData(entry.ExtraData);
 1829
 1830      if (entry.LocalHeaderRequiresZip64) {
 1831        ed.StartNewEntry();
 1832
 1833        // Local entry header always includes size and compressed size.
 1834        // NOTE the order of these fields is reversed when compared to the normal headers!
 1835        ed.AddLeLong(entry.Size);
 1836        ed.AddLeLong(entry.CompressedSize);
 1837        ed.AddNewEntry(1);
 1838      } else {
 1839        ed.Delete(1);
 1840      }
 1841
 1842      entry.ExtraData = ed.GetEntryData();
 1843
 1844      WriteLEShort(name.Length);
 1845      WriteLEShort(entry.ExtraData.Length);
 1846
 1847      if (name.Length > 0) {
 1848        baseStream_.Write(name, 0, name.Length);
 1849      }
 1850
 1851      if (entry.LocalHeaderRequiresZip64) {
 1852        if (!ed.Find(1)) {
 1853          throw new ZipException("Internal error cannot find extra data");
 1854        }
 1855
 1856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
 1857      }
 1858
 1859      if (entry.ExtraData.Length > 0) {
 1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
 1861      }
 1862    }
 1863
 1864    int WriteCentralDirectoryHeader(ZipEntry entry)
 1865    {
 1866      if (entry.CompressedSize < 0) {
 1867        throw new ZipException("Attempt to write central directory entry with unknown csize");
 1868      }
 1869
 1870      if (entry.Size < 0) {
 1871        throw new ZipException("Attempt to write central directory entry with unknown size");
 1872      }
 1873
 1874      if (entry.Crc < 0) {
 1875        throw new ZipException("Attempt to write central directory entry with unknown crc");
 1876      }
 1877
 1878      // Write the central file header
 1879      WriteLEInt(ZipConstants.CentralHeaderSignature);
 1880
 1881      // Version made by
 1882      WriteLEShort(ZipConstants.VersionMadeBy);
 1883
 1884      // Version required to extract
 1885      WriteLEShort(entry.Version);
 1886
 1887      WriteLEShort(entry.Flags);
 1888
 1889      unchecked {
 1890        WriteLEShort((byte)entry.CompressionMethod);
 1891        WriteLEInt((int)entry.DosTime);
 1892        WriteLEInt((int)entry.Crc);
 1893      }
 1894
 1895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {
 1896        WriteLEInt(-1);
 1897      } else {
 1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
 1899      }
 1900
 1901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {
 1902        WriteLEInt(-1);
 1903      } else {
 1904        WriteLEInt((int)entry.Size);
 1905      }
 1906
 1907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1908
 1909      if (name.Length > 0xFFFF) {
 1910        throw new ZipException("Entry name is too long.");
 1911      }
 1912
 1913      WriteLEShort(name.Length);
 1914
 1915      // Central header extra data is different to local header version so regenerate.
 1916      var ed = new ZipExtraData(entry.ExtraData);
 1917
 1918      if (entry.CentralHeaderRequiresZip64) {
 1919        ed.StartNewEntry();
 1920
 1921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1922          ed.AddLeLong(entry.Size);
 1923        }
 1924
 1925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 1926          ed.AddLeLong(entry.CompressedSize);
 1927        }
 1928
 1929        if (entry.Offset >= 0xffffffff) {
 1930          ed.AddLeLong(entry.Offset);
 1931        }
 1932
 1933        // Number of disk on which this file starts isnt supported and is never written here.
 1934        ed.AddNewEntry(1);
 1935      } else {
 1936        // Should have already be done when local header was added.
 1937        ed.Delete(1);
 1938      }
 1939
 1940      byte[] centralExtraData = ed.GetEntryData();
 1941
 1942      WriteLEShort(centralExtraData.Length);
 1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);
 1944
 1945      WriteLEShort(0);    // disk number
 1946      WriteLEShort(0);    // internal file attributes
 1947
 1948      // External file attributes...
 1949      if (entry.ExternalFileAttributes != -1) {
 1950        WriteLEInt(entry.ExternalFileAttributes);
 1951      } else {
 1952        if (entry.IsDirectory) {
 1953          WriteLEUint(16);
 1954        } else {
 1955          WriteLEUint(0);
 1956        }
 1957      }
 1958
 1959      if (entry.Offset >= 0xffffffff) {
 1960        WriteLEUint(0xffffffff);
 1961      } else {
 1962        WriteLEUint((uint)(int)entry.Offset);
 1963      }
 1964
 1965      if (name.Length > 0) {
 1966        baseStream_.Write(name, 0, name.Length);
 1967      }
 1968
 1969      if (centralExtraData.Length > 0) {
 1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
 1971      }
 1972
 1973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];
 1974
 1975      if (rawComment.Length > 0) {
 1976        baseStream_.Write(rawComment, 0, rawComment.Length);
 1977      }
 1978
 1979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
 1980    }
 1981    #endregion
 1982
 1983    void PostUpdateCleanup()
 1984    {
 1985      updateDataSource_ = null;
 1986      updates_ = null;
 1987      updateIndex_ = null;
 1988
 1989      if (archiveStorage_ != null) {
 1990        archiveStorage_.Dispose();
 1991        archiveStorage_ = null;
 1992      }
 1993    }
 1994
 1995    string GetTransformedFileName(string name)
 1996    {
 1997      INameTransform transform = NameTransform;
 1998      return (transform != null) ?
 1999        transform.TransformFile(name) :
 2000        name;
 2001    }
 2002
 2003    string GetTransformedDirectoryName(string name)
 2004    {
 2005      INameTransform transform = NameTransform;
 2006      return (transform != null) ?
 2007        transform.TransformDirectory(name) :
 2008        name;
 2009    }
 2010
 2011    /// <summary>
 2012    /// Get a raw memory buffer.
 2013    /// </summary>
 2014    /// <returns>Returns a raw memory buffer.</returns>
 2015    byte[] GetBuffer()
 2016    {
 2017      if (copyBuffer_ == null) {
 2018        copyBuffer_ = new byte[bufferSize_];
 2019      }
 2020      return copyBuffer_;
 2021    }
 2022
 2023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)
 2024    {
 2025      int bytesToCopy = GetDescriptorSize(update);
 2026
 2027      if (bytesToCopy > 0) {
 2028        byte[] buffer = GetBuffer();
 2029
 2030        while (bytesToCopy > 0) {
 2031          int readSize = Math.Min(buffer.Length, bytesToCopy);
 2032
 2033          int bytesRead = source.Read(buffer, 0, readSize);
 2034          if (bytesRead > 0) {
 2035            dest.Write(buffer, 0, bytesRead);
 2036            bytesToCopy -= bytesRead;
 2037          } else {
 2038            throw new ZipException("Unxpected end of stream");
 2039          }
 2040        }
 2041      }
 2042    }
 2043
 2044    void CopyBytes(ZipUpdate update, Stream destination, Stream source,
 2045      long bytesToCopy, bool updateCrc)
 2046    {
 2047      if (destination == source) {
 2048        throw new InvalidOperationException("Destination and source are the same");
 2049      }
 2050
 2051      // NOTE: Compressed size is updated elsewhere.
 2052      var crc = new Crc32();
 2053      byte[] buffer = GetBuffer();
 2054
 2055      long targetBytes = bytesToCopy;
 2056      long totalBytesRead = 0;
 2057
 2058      int bytesRead;
 2059      do {
 2060        int readSize = buffer.Length;
 2061
 2062        if (bytesToCopy < readSize) {
 2063          readSize = (int)bytesToCopy;
 2064        }
 2065
 2066        bytesRead = source.Read(buffer, 0, readSize);
 2067        if (bytesRead > 0) {
 2068          if (updateCrc) {
 2069            crc.Update(buffer, 0, bytesRead);
 2070          }
 2071          destination.Write(buffer, 0, bytesRead);
 2072          bytesToCopy -= bytesRead;
 2073          totalBytesRead += bytesRead;
 2074        }
 2075      }
 2076      while ((bytesRead > 0) && (bytesToCopy > 0));
 2077
 2078      if (totalBytesRead != targetBytes) {
 2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2080      }
 2081
 2082      if (updateCrc) {
 2083        update.OutEntry.Crc = crc.Value;
 2084      }
 2085    }
 2086
 2087    /// <summary>
 2088    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
 2089    /// </summary>
 2090    /// <param name="update">The update to get the size for.</param>
 2091    /// <returns>The descriptor size, zero if there isnt one.</returns>
 2092    int GetDescriptorSize(ZipUpdate update)
 2093    {
 2094      int result = 0;
 2095      if ((update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 2096        result = ZipConstants.DataDescriptorSize - 4;
 2097        if (update.Entry.LocalHeaderRequiresZip64) {
 2098          result = ZipConstants.Zip64DataDescriptorSize - 4;
 2099        }
 2100      }
 2101      return result;
 2102    }
 2103
 2104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
 2105    {
 2106      int bytesToCopy = GetDescriptorSize(update);
 2107
 2108      while (bytesToCopy > 0) {
 2109        var readSize = (int)bytesToCopy;
 2110        byte[] buffer = GetBuffer();
 2111
 2112        stream.Position = sourcePosition;
 2113        int bytesRead = stream.Read(buffer, 0, readSize);
 2114        if (bytesRead > 0) {
 2115          stream.Position = destinationPosition;
 2116          stream.Write(buffer, 0, bytesRead);
 2117          bytesToCopy -= bytesRead;
 2118          destinationPosition += bytesRead;
 2119          sourcePosition += bytesRead;
 2120        } else {
 2121          throw new ZipException("Unxpected end of stream");
 2122        }
 2123      }
 2124    }
 2125
 2126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou
 2127    {
 2128      long bytesToCopy = update.Entry.CompressedSize;
 2129
 2130      // NOTE: Compressed size is updated elsewhere.
 2131      var crc = new Crc32();
 2132      byte[] buffer = GetBuffer();
 2133
 2134      long targetBytes = bytesToCopy;
 2135      long totalBytesRead = 0;
 2136
 2137      int bytesRead;
 2138      do {
 2139        int readSize = buffer.Length;
 2140
 2141        if (bytesToCopy < readSize) {
 2142          readSize = (int)bytesToCopy;
 2143        }
 2144
 2145        stream.Position = sourcePosition;
 2146        bytesRead = stream.Read(buffer, 0, readSize);
 2147        if (bytesRead > 0) {
 2148          if (updateCrc) {
 2149            crc.Update(buffer, 0, bytesRead);
 2150          }
 2151          stream.Position = destinationPosition;
 2152          stream.Write(buffer, 0, bytesRead);
 2153
 2154          destinationPosition += bytesRead;
 2155          sourcePosition += bytesRead;
 2156          bytesToCopy -= bytesRead;
 2157          totalBytesRead += bytesRead;
 2158        }
 2159      }
 2160      while ((bytesRead > 0) && (bytesToCopy > 0));
 2161
 2162      if (totalBytesRead != targetBytes) {
 2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2164      }
 2165
 2166      if (updateCrc) {
 2167        update.OutEntry.Crc = crc.Value;
 2168      }
 2169    }
 2170
 2171    int FindExistingUpdate(ZipEntry entry)
 2172    {
 2173      int result = -1;
 2174      string convertedName = GetTransformedFileName(entry.Name);
 2175
 2176      if (updateIndex_.ContainsKey(convertedName)) {
 2177        result = (int)updateIndex_[convertedName];
 2178      }
 2179      /*
 2180            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2181            // for CF?
 2182            for (int index = 0; index < updates_.Count; ++index)
 2183            {
 2184              ZipUpdate zu = ( ZipUpdate )updates_[index];
 2185              if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
 2186                (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
 2187                result = index;
 2188                break;
 2189              }
 2190            }
 2191       */
 2192      return result;
 2193    }
 2194
 2195    int FindExistingUpdate(string fileName)
 2196    {
 2197      int result = -1;
 2198
 2199      string convertedName = GetTransformedFileName(fileName);
 2200
 2201      if (updateIndex_.ContainsKey(convertedName)) {
 2202        result = (int)updateIndex_[convertedName];
 2203      }
 2204
 2205      /*
 2206            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2207            // for CF?
 2208            for ( int index = 0; index < updates_.Count; ++index ) {
 2209              if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,
 2210                true, CultureInfo.InvariantCulture) == 0 ) {
 2211                result = index;
 2212                break;
 2213              }
 2214            }
 2215       */
 2216
 2217      return result;
 2218    }
 2219
 2220    /// <summary>
 2221    /// Get an output stream for the specified <see cref="ZipEntry"/>
 2222    /// </summary>
 2223    /// <param name="entry">The entry to get an output stream for.</param>
 2224    /// <returns>The output stream obtained for the entry.</returns>
 2225    Stream GetOutputStream(ZipEntry entry)
 2226    {
 2227      Stream result = baseStream_;
 2228
 2229      if (entry.IsCrypted == true) {
 2230        result = CreateAndInitEncryptionStream(result, entry);
 2231      }
 2232
 2233      switch (entry.CompressionMethod) {
 2234        case CompressionMethod.Stored:
 2235          result = new UncompressedStream(result);
 2236          break;
 2237
 2238        case CompressionMethod.Deflated:
 2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));
 2240          dos.IsStreamOwner = false;
 2241          result = dos;
 2242          break;
 2243
 2244        default:
 2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);
 2246      }
 2247      return result;
 2248    }
 2249
 2250    void AddEntry(ZipFile workFile, ZipUpdate update)
 2251    {
 2252      Stream source = null;
 2253
 2254      if (update.Entry.IsFile) {
 2255        source = update.GetSource();
 2256
 2257        if (source == null) {
 2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);
 2259        }
 2260      }
 2261
 2262      if (source != null) {
 2263        using (source) {
 2264          long sourceStreamLength = source.Length;
 2265          if (update.OutEntry.Size < 0) {
 2266            update.OutEntry.Size = sourceStreamLength;
 2267          } else {
 2268            // Check for errant entries.
 2269            if (update.OutEntry.Size != sourceStreamLength) {
 2270              throw new ZipException("Entry size/stream size mismatch");
 2271            }
 2272          }
 2273
 2274          workFile.WriteLocalEntryHeader(update);
 2275
 2276          long dataStart = workFile.baseStream_.Position;
 2277
 2278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2279            CopyBytes(update, output, source, sourceStreamLength, true);
 2280          }
 2281
 2282          long dataEnd = workFile.baseStream_.Position;
 2283          update.OutEntry.CompressedSize = dataEnd - dataStart;
 2284
 2285          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor) {
 2286            var helper = new ZipHelperStream(workFile.baseStream_);
 2287            helper.WriteDataDescriptor(update.OutEntry);
 2288          }
 2289        }
 2290      } else {
 2291        workFile.WriteLocalEntryHeader(update);
 2292        update.OutEntry.CompressedSize = 0;
 2293      }
 2294
 2295    }
 2296
 2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)
 2298    {
 2299      workFile.WriteLocalEntryHeader(update);
 2300      long dataStart = workFile.baseStream_.Position;
 2301
 2302      // TODO: This is slow if the changes don't effect the data!!
 2303      if (update.Entry.IsFile && (update.Filename != null)) {
 2304        using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 2305          using (Stream source = this.GetInputStream(update.Entry)) {
 2306            CopyBytes(update, output, source, source.Length, true);
 2307          }
 2308        }
 2309      }
 2310
 2311      long dataEnd = workFile.baseStream_.Position;
 2312      update.Entry.CompressedSize = dataEnd - dataStart;
 2313    }
 2314
 2315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)
 2316    {
 2317      bool skipOver = false || update.Entry.Offset == destinationPosition;
 2318
 2319      if (!skipOver) {
 2320        baseStream_.Position = destinationPosition;
 2321        workFile.WriteLocalEntryHeader(update);
 2322        destinationPosition = baseStream_.Position;
 2323      }
 2324
 2325      long sourcePosition = 0;
 2326
 2327      const int NameLengthOffset = 26;
 2328
 2329      // TODO: Add base for SFX friendly handling
 2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2331
 2332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2333
 2334      // Clumsy way of handling retrieving the original name and extra data length for now.
 2335      // TODO: Stop re-reading name and data length in CopyEntryDirect.
 2336      uint nameLength = ReadLEUshort();
 2337      uint extraLength = ReadLEUshort();
 2338
 2339      sourcePosition = baseStream_.Position + nameLength + extraLength;
 2340
 2341      if (skipOver) {
 2342        if (update.OffsetBasedSize != -1)
 2343          destinationPosition += update.OffsetBasedSize;
 2344        else
 2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar
 2346          // WinZip produces a warning on these entries:
 2347          // "caution: value of lrec.csize (compressed size) changed from ..."
 2348          destinationPosition +=
 2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size
 2350            update.Entry.CompressedSize + GetDescriptorSize(update);
 2351      } else {
 2352        if (update.Entry.CompressedSize > 0) {
 2353          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition);
 2354        }
 2355        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
 2356      }
 2357    }
 2358
 2359    void CopyEntry(ZipFile workFile, ZipUpdate update)
 2360    {
 2361      workFile.WriteLocalEntryHeader(update);
 2362
 2363      if (update.Entry.CompressedSize > 0) {
 2364        const int NameLengthOffset = 26;
 2365
 2366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2367
 2368        // TODO: This wont work for SFX files!
 2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2370
 2371        uint nameLength = ReadLEUshort();
 2372        uint extraLength = ReadLEUshort();
 2373
 2374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);
 2375
 2376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
 2377      }
 2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
 2379    }
 2380
 2381    void Reopen(Stream source)
 2382    {
 2383      if (source == null) {
 2384        throw new ZipException("Failed to reopen archive - no source");
 2385      }
 2386
 2387      isNewArchive_ = false;
 2388      baseStream_ = source;
 2389      ReadEntries();
 2390    }
 2391
 2392    void Reopen()
 2393    {
 2394      if (Name == null) {
 2395        throw new InvalidOperationException("Name is not known cannot Reopen");
 2396      }
 2397
 2398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));
 2399    }
 2400
 2401    void UpdateCommentOnly()
 2402    {
 2403      long baseLength = baseStream_.Length;
 2404
 2405      ZipHelperStream updateFile = null;
 2406
 2407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
 2409        updateFile = new ZipHelperStream(copyStream);
 2410        updateFile.IsStreamOwner = true;
 2411
 2412        baseStream_.Close();
 2413        baseStream_ = null;
 2414      } else {
 2415        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2416          // TODO: archiveStorage wasnt originally intended for this use.
 2417          // Need to revisit this to tidy up handling as archive storage currently doesnt
 2418          // handle the original stream well.
 2419          // The problem is when using an existing zip archive with an in memory archive storage.
 2420          // The open stream wont support writing but the memory storage should open the same file not an in memory one.
 2421
 2422          // Need to tidy up the archive storage interface and contract basically.
 2423          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);
 2424          updateFile = new ZipHelperStream(baseStream_);
 2425        } else {
 2426          baseStream_.Close();
 2427          baseStream_ = null;
 2428          updateFile = new ZipHelperStream(Name);
 2429        }
 2430      }
 2431
 2432      using (updateFile) {
 2433        long locatedCentralDirOffset =
 2434          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2435                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2436        if (locatedCentralDirOffset < 0) {
 2437          throw new ZipException("Cannot find central directory");
 2438        }
 2439
 2440        const int CentralHeaderCommentSizeOffset = 16;
 2441        updateFile.Position += CentralHeaderCommentSizeOffset;
 2442
 2443        byte[] rawComment = newComment_.RawComment;
 2444
 2445        updateFile.WriteLEShort(rawComment.Length);
 2446        updateFile.Write(rawComment, 0, rawComment.Length);
 2447        updateFile.SetLength(updateFile.Position);
 2448      }
 2449
 2450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2452      } else {
 2453        ReadEntries();
 2454      }
 2455    }
 2456
 2457    /// <summary>
 2458    /// Class used to sort updates.
 2459    /// </summary>
 2460    class UpdateComparer : IComparer
 2461    {
 2462      /// <summary>
 2463      /// Compares two objects and returns a value indicating whether one is
 2464      /// less than, equal to or greater than the other.
 2465      /// </summary>
 2466      /// <param name="x">First object to compare</param>
 2467      /// <param name="y">Second object to compare.</param>
 2468      /// <returns>Compare result.</returns>
 2469      public int Compare(
 2470        object x,
 2471        object y)
 2472      {
 2473        var zx = x as ZipUpdate;
 2474        var zy = y as ZipUpdate;
 2475
 2476        int result;
 2477
 2478        if (zx == null) {
 2479          if (zy == null) {
 2480            result = 0;
 2481          } else {
 2482            result = -1;
 2483          }
 2484        } else if (zy == null) {
 2485          result = 1;
 2486        } else {
 2487          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;
 2488          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;
 2489
 2490          result = xCmdValue - yCmdValue;
 2491          if (result == 0) {
 2492            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;
 2493            if (offsetDiff < 0) {
 2494              result = -1;
 2495            } else if (offsetDiff == 0) {
 2496              result = 0;
 2497            } else {
 2498              result = 1;
 2499            }
 2500          }
 2501        }
 2502        return result;
 2503      }
 2504    }
 2505
 2506    void RunUpdates()
 2507    {
 2508      long sizeEntries = 0;
 2509      long endOfStream = 0;
 2510      bool directUpdate = false;
 2511      long destinationPosition = 0; // NOT SFX friendly
 2512
 2513      ZipFile workFile;
 2514
 2515      if (IsNewArchive) {
 2516        workFile = this;
 2517        workFile.baseStream_.Position = 0;
 2518        directUpdate = true;
 2519      } else if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2520        workFile = this;
 2521        workFile.baseStream_.Position = 0;
 2522        directUpdate = true;
 2523
 2524        // Sort the updates by offset within copies/modifies, then adds.
 2525        // This ensures that data required by copies will not be overwritten.
 2526        updates_.Sort(new UpdateComparer());
 2527      } else {
 2528        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
 2529        workFile.UseZip64 = UseZip64;
 2530
 2531        if (key != null) {
 2532          workFile.key = (byte[])key.Clone();
 2533        }
 2534      }
 2535
 2536      try {
 2537        foreach (ZipUpdate update in updates_) {
 2538          if (update != null) {
 2539            switch (update.Command) {
 2540              case UpdateCommand.Copy:
 2541                if (directUpdate) {
 2542                  CopyEntryDirect(workFile, update, ref destinationPosition);
 2543                } else {
 2544                  CopyEntry(workFile, update);
 2545                }
 2546                break;
 2547
 2548              case UpdateCommand.Modify:
 2549                // TODO: Direct modifying of an entry will take some legwork.
 2550                ModifyEntry(workFile, update);
 2551                break;
 2552
 2553              case UpdateCommand.Add:
 2554                if (!IsNewArchive && directUpdate) {
 2555                  workFile.baseStream_.Position = destinationPosition;
 2556                }
 2557
 2558                AddEntry(workFile, update);
 2559
 2560                if (directUpdate) {
 2561                  destinationPosition = workFile.baseStream_.Position;
 2562                }
 2563                break;
 2564            }
 2565          }
 2566        }
 2567
 2568        if (!IsNewArchive && directUpdate) {
 2569          workFile.baseStream_.Position = destinationPosition;
 2570        }
 2571
 2572        long centralDirOffset = workFile.baseStream_.Position;
 2573
 2574        foreach (ZipUpdate update in updates_) {
 2575          if (update != null) {
 2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
 2577          }
 2578        }
 2579
 2580        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 2581        using (ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_)) {
 2582          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);
 2583        }
 2584
 2585        endOfStream = workFile.baseStream_.Position;
 2586
 2587        // And now patch entries...
 2588        foreach (ZipUpdate update in updates_) {
 2589          if (update != null) {
 2590            // If the size of the entry is zero leave the crc as 0 as well.
 2591            // The calculated crc will be all bits on...
 2592            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {
 2593              workFile.baseStream_.Position = update.CrcPatchOffset;
 2594              workFile.WriteLEInt((int)update.OutEntry.Crc);
 2595            }
 2596
 2597            if (update.SizePatchOffset > 0) {
 2598              workFile.baseStream_.Position = update.SizePatchOffset;
 2599              if (update.OutEntry.LocalHeaderRequiresZip64) {
 2600                workFile.WriteLeLong(update.OutEntry.Size);
 2601                workFile.WriteLeLong(update.OutEntry.CompressedSize);
 2602              } else {
 2603                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);
 2604                workFile.WriteLEInt((int)update.OutEntry.Size);
 2605              }
 2606            }
 2607          }
 2608        }
 2609      } catch {
 2610        workFile.Close();
 2611        if (!directUpdate && (workFile.Name != null)) {
 2612          File.Delete(workFile.Name);
 2613        }
 2614        throw;
 2615      }
 2616
 2617      if (directUpdate) {
 2618        workFile.baseStream_.SetLength(endOfStream);
 2619        workFile.baseStream_.Flush();
 2620        isNewArchive_ = false;
 2621        ReadEntries();
 2622      } else {
 2623        baseStream_.Close();
 2624        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2625      }
 2626    }
 2627
 2628    void CheckUpdating()
 2629    {
 2630      if (updates_ == null) {
 2631        throw new InvalidOperationException("BeginUpdate has not been called");
 2632      }
 2633    }
 2634
 2635    #endregion
 2636
 2637    #region ZipUpdate class
 2638    /// <summary>
 2639    /// Represents a pending update to a Zip file.
 2640    /// </summary>
 2641    class ZipUpdate
 2642    {
 2643      #region Constructors
 2644      public ZipUpdate(string fileName, ZipEntry entry)
 2645      {
 2646        command_ = UpdateCommand.Add;
 2647        entry_ = entry;
 2648        filename_ = fileName;
 2649      }
 2650
 2651      [Obsolete]
 2652      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 2653      {
 2654        command_ = UpdateCommand.Add;
 2655        entry_ = new ZipEntry(entryName);
 2656        entry_.CompressionMethod = compressionMethod;
 2657        filename_ = fileName;
 2658      }
 2659
 2660      [Obsolete]
 2661      public ZipUpdate(string fileName, string entryName)
 2662        : this(fileName, entryName, CompressionMethod.Deflated)
 2663      {
 2664        // Do nothing.
 2665      }
 2666
 2667      [Obsolete]
 2668      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 2669      {
 2670        command_ = UpdateCommand.Add;
 2671        entry_ = new ZipEntry(entryName);
 2672        entry_.CompressionMethod = compressionMethod;
 2673        dataSource_ = dataSource;
 2674      }
 2675
 2676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 2677      {
 2678        command_ = UpdateCommand.Add;
 2679        entry_ = entry;
 2680        dataSource_ = dataSource;
 2681      }
 2682
 2683      public ZipUpdate(ZipEntry original, ZipEntry updated)
 2684      {
 2685        throw new ZipException("Modify not currently supported");
 2686        /*
 2687          command_ = UpdateCommand.Modify;
 2688          entry_ = ( ZipEntry )original.Clone();
 2689          outEntry_ = ( ZipEntry )updated.Clone();
 2690        */
 2691      }
 2692
 2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)
 2694      {
 2695        command_ = command;
 2696        entry_ = (ZipEntry)entry.Clone();
 2697      }
 2698
 2699
 2700      /// <summary>
 2701      /// Copy an existing entry.
 2702      /// </summary>
 2703      /// <param name="entry">The existing entry to copy.</param>
 2704      public ZipUpdate(ZipEntry entry)
 2705        : this(UpdateCommand.Copy, entry)
 2706      {
 2707        // Do nothing.
 2708      }
 2709      #endregion
 2710
 2711      /// <summary>
 2712      /// Get the <see cref="ZipEntry"/> for this update.
 2713      /// </summary>
 2714      /// <remarks>This is the source or original entry.</remarks>
 2715      public ZipEntry Entry {
 2716        get { return entry_; }
 2717      }
 2718
 2719      /// <summary>
 2720      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.
 2721      /// </summary>
 2722      public ZipEntry OutEntry {
 2723        get {
 2724          if (outEntry_ == null) {
 2725            outEntry_ = (ZipEntry)entry_.Clone();
 2726          }
 2727
 2728          return outEntry_;
 2729        }
 2730      }
 2731
 2732      /// <summary>
 2733      /// Get the command for this update.
 2734      /// </summary>
 2735      public UpdateCommand Command {
 2736        get { return command_; }
 2737      }
 2738
 2739      /// <summary>
 2740      /// Get the filename if any for this update.  Null if none exists.
 2741      /// </summary>
 2742      public string Filename {
 2743        get { return filename_; }
 2744      }
 2745
 2746      /// <summary>
 2747      /// Get/set the location of the size patch for this update.
 2748      /// </summary>
 2749      public long SizePatchOffset {
 2750        get { return sizePatchOffset_; }
 2751        set { sizePatchOffset_ = value; }
 2752      }
 2753
 2754      /// <summary>
 2755      /// Get /set the location of the crc patch for this update.
 2756      /// </summary>
 2757      public long CrcPatchOffset {
 2758        get { return crcPatchOffset_; }
 2759        set { crcPatchOffset_ = value; }
 2760      }
 2761
 2762      /// <summary>
 2763      /// Get/set the size calculated by offset.
 2764      /// Specifically, the difference between this and next entry's starting offset.
 2765      /// </summary>
 2766      public long OffsetBasedSize {
 2767        get { return _offsetBasedSize; }
 2768        set { _offsetBasedSize = value; }
 2769      }
 2770
 2771      public Stream GetSource()
 2772      {
 2773        Stream result = null;
 2774        if (dataSource_ != null) {
 2775          result = dataSource_.GetSource();
 2776        }
 2777
 2778        return result;
 2779      }
 2780
 2781      #region Instance Fields
 2782      ZipEntry entry_;
 2783      ZipEntry outEntry_;
 2784      UpdateCommand command_;
 2785      IStaticDataSource dataSource_;
 2786      string filename_;
 2787      long sizePatchOffset_ = -1;
 2788      long crcPatchOffset_ = -1;
 2789      long _offsetBasedSize = -1;
 2790      #endregion
 2791    }
 2792
 2793    #endregion
 2794    #endregion
 2795
 2796    #region Disposing
 2797
 2798    #region IDisposable Members
 2799    void IDisposable.Dispose()
 2800    {
 2801      Close();
 2802    }
 2803    #endregion
 2804
 2805    void DisposeInternal(bool disposing)
 2806    {
 2807      if (!isDisposed_) {
 2808        isDisposed_ = true;
 2809        entries_ = new ZipEntry[0];
 2810
 2811        if (IsStreamOwner && (baseStream_ != null)) {
 2812          lock (baseStream_) {
 2813            baseStream_.Close();
 2814          }
 2815        }
 2816
 2817        PostUpdateCleanup();
 2818      }
 2819    }
 2820
 2821    /// <summary>
 2822    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.
 2823    /// </summary>
 2824    /// <param name="disposing">true to release both managed and unmanaged resources;
 2825    /// false to release only unmanaged resources.</param>
 2826    protected virtual void Dispose(bool disposing)
 2827    {
 2828      DisposeInternal(disposing);
 2829    }
 2830
 2831    #endregion
 2832
 2833    #region Internal routines
 2834    #region Reading
 2835    /// <summary>
 2836    /// Read an unsigned short in little endian byte order.
 2837    /// </summary>
 2838    /// <returns>Returns the value read.</returns>
 2839    /// <exception cref="EndOfStreamException">
 2840    /// The stream ends prematurely
 2841    /// </exception>
 2842    ushort ReadLEUshort()
 2843    {
 2844      int data1 = baseStream_.ReadByte();
 2845
 2846      if (data1 < 0) {
 2847        throw new EndOfStreamException("End of stream");
 2848      }
 2849
 2850      int data2 = baseStream_.ReadByte();
 2851
 2852      if (data2 < 0) {
 2853        throw new EndOfStreamException("End of stream");
 2854      }
 2855
 2856
 2857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));
 2858    }
 2859
 2860    /// <summary>
 2861    /// Read a uint in little endian byte order.
 2862    /// </summary>
 2863    /// <returns>Returns the value read.</returns>
 2864    /// <exception cref="IOException">
 2865    /// An i/o error occurs.
 2866    /// </exception>
 2867    /// <exception cref="System.IO.EndOfStreamException">
 2868    /// The file ends prematurely
 2869    /// </exception>
 2870    uint ReadLEUint()
 2871    {
 2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));
 2873    }
 2874
 2875    ulong ReadLEUlong()
 2876    {
 2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);
 2878    }
 2879
 2880    #endregion
 2881    // NOTE this returns the offset of the first byte after the signature.
 2882    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 2883    {
 2884      using (ZipHelperStream les = new ZipHelperStream(baseStream_)) {
 2885        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
 2886      }
 2887    }
 2888
 2889    /// <summary>
 2890    /// Search for and read the central directory of a zip file filling the entries array.
 2891    /// </summary>
 2892    /// <exception cref="System.IO.IOException">
 2893    /// An i/o error occurs.
 2894    /// </exception>
 2895    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 2896    /// The central directory is malformed or cannot be found
 2897    /// </exception>
 2898    void ReadEntries()
 2899    {
 2900      // Search for the End Of Central Directory.  When a zip comment is
 2901      // present the directory will start earlier
 2902      //
 2903      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
 2904      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
 2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
 2906      // this could be invalid.
 2907      // Could also speed this up by reading memory in larger blocks.
 2908
 2909      if (baseStream_.CanSeek == false) {
 2910        throw new ZipException("ZipFile stream must be seekable");
 2911      }
 2912
 2913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2915
 2916      if (locatedEndOfCentralDir < 0) {
 2917        throw new ZipException("Cannot find central directory");
 2918      }
 2919
 2920      // Read end of central directory record
 2921      ushort thisDiskNumber = ReadLEUshort();
 2922      ushort startCentralDirDisk = ReadLEUshort();
 2923      ulong entriesForThisDisk = ReadLEUshort();
 2924      ulong entriesForWholeCentralDir = ReadLEUshort();
 2925      ulong centralDirSize = ReadLEUint();
 2926      long offsetOfCentralDir = ReadLEUint();
 2927      uint commentSize = ReadLEUshort();
 2928
 2929      if (commentSize > 0) {
 2930        byte[] comment = new byte[commentSize];
 2931
 2932        StreamUtils.ReadFully(baseStream_, comment);
 2933        comment_ = ZipConstants.ConvertToString(comment);
 2934      } else {
 2935        comment_ = string.Empty;
 2936      }
 2937
 2938      bool isZip64 = false;
 2939
 2940      // Check if zip64 header information is required.
 2941      if ((thisDiskNumber == 0xffff) ||
 2942        (startCentralDirDisk == 0xffff) ||
 2943        (entriesForThisDisk == 0xffff) ||
 2944        (entriesForWholeCentralDir == 0xffff) ||
 2945        (centralDirSize == 0xffffffff) ||
 2946        (offsetOfCentralDir == 0xffffffff)) {
 2947        isZip64 = true;
 2948
 2949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 
 2950        if (offset < 0) {
 2951          throw new ZipException("Cannot find Zip64 locator");
 2952        }
 2953
 2954        // number of the disk with the start of the zip64 end of central directory 4 bytes
 2955        // relative offset of the zip64 end of central directory record 8 bytes
 2956        // total number of disks 4 bytes
 2957        ReadLEUint(); // startDisk64 is not currently used
 2958        ulong offset64 = ReadLEUlong();
 2959        uint totalDisks = ReadLEUint();
 2960
 2961        baseStream_.Position = (long)offset64;
 2962        long sig64 = ReadLEUint();
 2963
 2964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {
 2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
 2966        }
 2967
 2968        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
 2969        ulong recordSize = ReadLEUlong();
 2970        int versionMadeBy = ReadLEUshort();
 2971        int versionToExtract = ReadLEUshort();
 2972        uint thisDisk = ReadLEUint();
 2973        uint centralDirDisk = ReadLEUint();
 2974        entriesForThisDisk = ReadLEUlong();
 2975        entriesForWholeCentralDir = ReadLEUlong();
 2976        centralDirSize = ReadLEUlong();
 2977        offsetOfCentralDir = (long)ReadLEUlong();
 2978
 2979        // NOTE: zip64 extensible data sector (variable size) is ignored.
 2980      }
 2981
 2982      entries_ = new ZipEntry[entriesForThisDisk];
 2983
 2984      // SFX/embedded support, find the offset of the first entry vis the start of the stream
 2985      // This applies to Zip files that are appended to the end of an SFX stub.
 2986      // Or are appended as a resource to an executable.
 2987      // Zip files created by some archivers have the offsets altered to reflect the true offsets
 2988      // and so dont require any adjustment here...
 2989      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
 2990      if (!isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize))) {
 2991        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
 2992        if (offsetOfFirstEntry <= 0) {
 2993          throw new ZipException("Invalid embedded zip archive");
 2994        }
 2995      }
 2996
 2997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
 2998
 2999      for (ulong i = 0; i < entriesForThisDisk; i++) {
 3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
 3001          throw new ZipException("Wrong Central Directory signature");
 3002        }
 3003
 3004        int versionMadeBy = ReadLEUshort();
 3005        int versionToExtract = ReadLEUshort();
 3006        int bitFlags = ReadLEUshort();
 3007        int method = ReadLEUshort();
 3008        uint dostime = ReadLEUint();
 3009        uint crc = ReadLEUint();
 3010        var csize = (long)ReadLEUint();
 3011        var size = (long)ReadLEUint();
 3012        int nameLen = ReadLEUshort();
 3013        int extraLen = ReadLEUshort();
 3014        int commentLen = ReadLEUshort();
 3015
 3016        int diskStartNo = ReadLEUshort();  // Not currently used
 3017        int internalAttributes = ReadLEUshort();  // Not currently used
 3018
 3019        uint externalAttributes = ReadLEUint();
 3020        long offset = ReadLEUint();
 3021
 3022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
 3023
 3024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
 3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);
 3026
 3027        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
 3028        entry.Crc = crc & 0xffffffffL;
 3029        entry.Size = size & 0xffffffffL;
 3030        entry.CompressedSize = csize & 0xffffffffL;
 3031        entry.Flags = bitFlags;
 3032        entry.DosTime = (uint)dostime;
 3033        entry.ZipFileIndex = (long)i;
 3034        entry.Offset = offset;
 3035        entry.ExternalFileAttributes = (int)externalAttributes;
 3036
 3037        if ((bitFlags & 8) == 0) {
 3038          entry.CryptoCheckValue = (byte)(crc >> 24);
 3039        } else {
 3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
 3041        }
 3042
 3043        if (extraLen > 0) {
 3044          byte[] extra = new byte[extraLen];
 3045          StreamUtils.ReadFully(baseStream_, extra);
 3046          entry.ExtraData = extra;
 3047        }
 3048
 3049        entry.ProcessExtraData(false);
 3050
 3051        if (commentLen > 0) {
 3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
 3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
 3054        }
 3055
 3056        entries_[i] = entry;
 3057      }
 3058    }
 3059
 3060    /// <summary>
 3061    /// Locate the data for a given entry.
 3062    /// </summary>
 3063    /// <returns>
 3064    /// The start offset of the data.
 3065    /// </returns>
 3066    /// <exception cref="System.IO.EndOfStreamException">
 3067    /// The stream ends prematurely
 3068    /// </exception>
 3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 3070    /// The local header signature is invalid, the entry and central header file name lengths are different
 3071    /// or the local and entry compression methods dont match
 3072    /// </exception>
 3073    long LocateEntry(ZipEntry entry)
 3074    {
 3075      return TestLocalHeader(entry, HeaderTest.Extract);
 3076    }
 3077
 3078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
 3079    {
 3080      CryptoStream result = null;
 3081
 3082      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3084        var classicManaged = new PkzipClassicManaged();
 3085
 3086        OnKeysRequired(entry.Name);
 3087        if (HaveKeys == false) {
 3088          throw new ZipException("No password available for encrypted stream");
 3089        }
 3090
 3091        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
 3092        CheckClassicPassword(result, entry);
 3093      } else {
 3094        if (entry.Version == ZipConstants.VERSION_AES) {
 3095          //
 3096          OnKeysRequired(entry.Name);
 3097          if (HaveKeys == false) {
 3098            throw new ZipException("No password available for AES encrypted stream");
 3099          }
 3100          int saltLen = entry.AESSaltLen;
 3101          byte[] saltBytes = new byte[saltLen];
 3102          int saltIn = baseStream.Read(saltBytes, 0, saltLen);
 3103          if (saltIn != saltLen)
 3104            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
 3105          //
 3106          byte[] pwdVerifyRead = new byte[2];
 3107          baseStream.Read(pwdVerifyRead, 0, 2);
 3108          int blockSize = entry.AESKeySize / 8;   // bits to bytes
 3109
 3110          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
 3111          byte[] pwdVerifyCalc = decryptor.PwdVerifier;
 3112          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
 3113            throw new ZipException("Invalid password for AES");
 3114          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
 3115        } else {
 3116          throw new ZipException("Decryption method not supported");
 3117        }
 3118      }
 3119
 3120      return result;
 3121    }
 3122
 3123    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
 3124    {
 3125      CryptoStream result = null;
 3126      if ((entry.Version < ZipConstants.VersionStrongEncryption)
 3127        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 3128        var classicManaged = new PkzipClassicManaged();
 3129
 3130        OnKeysRequired(entry.Name);
 3131        if (HaveKeys == false) {
 3132          throw new ZipException("No password available for encrypted stream");
 3133        }
 3134
 3135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
 3136        // which doesnt do this.
 3137        result = new CryptoStream(new UncompressedStream(baseStream),
 3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
 3139
 3140        if ((entry.Crc < 0) || (entry.Flags & 8) != 0) {
 3141          WriteEncryptionHeader(result, entry.DosTime << 16);
 3142        } else {
 3143          WriteEncryptionHeader(result, entry.Crc);
 3144        }
 3145      }
 3146      return result;
 3147    }
 3148
 3149    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
 3150    {
 3151      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
 3152      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
 3153      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
 3154        throw new ZipException("Invalid password");
 3155      }
 3156    }
 3157
 3158    static void WriteEncryptionHeader(Stream stream, long crcValue)
 3159    {
 3160      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
 3161      var rnd = new Random();
 3162      rnd.NextBytes(cryptBuffer);
 3163      cryptBuffer[11] = (byte)(crcValue >> 24);
 3164      stream.Write(cryptBuffer, 0, cryptBuffer.Length);
 3165    }
 3166
 3167    #endregion
 3168
 3169    #region Instance Fields
 3170    bool isDisposed_;
 3171    string name_;
 3172    string comment_;
 3173    string rawPassword_;
 3174    Stream baseStream_;
 3175    bool isStreamOwner;
 3176    long offsetOfFirstEntry;
 3177    ZipEntry[] entries_;
 3178    byte[] key;
 3179    bool isNewArchive_;
 3180
 3181    // Default is dynamic which is not backwards compatible and can cause problems
 3182    // with XP's built in compression which cant read Zip64 archives.
 3183    // However it does avoid the situation were a large file is added and cannot be completed correctly.
 3184    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.
 3185    UseZip64 useZip64_ = UseZip64.Dynamic;
 3186
 3187    #region Zip Update Instance Fields
 3188    ArrayList updates_;
 3189    long updateCount_; // Count is managed manually as updates_ can contain nulls!
 3190    Hashtable updateIndex_;
 3191    IArchiveStorage archiveStorage_;
 3192    IDynamicDataSource updateDataSource_;
 3193    bool contentsEdited_;
 3194    int bufferSize_ = DefaultBufferSize;
 3195    byte[] copyBuffer_;
 3196    ZipString newComment_;
 3197    bool commentEdited_;
 3198    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();
 3199    #endregion
 3200    #endregion
 3201
 3202    #region Support Classes
 3203    /// <summary>
 3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.
 3205    /// </summary>
 3206    class ZipString
 3207    {
 3208      #region Constructors
 3209      /// <summary>
 3210      /// Initialise a <see cref="ZipString"/> with a string.
 3211      /// </summary>
 3212      /// <param name="comment">The textual string form.</param>
 3213      public ZipString(string comment)
 3214      {
 3215        comment_ = comment;
 3216        isSourceString_ = true;
 3217      }
 3218
 3219      /// <summary>
 3220      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.
 3221      /// </summary>
 3222      /// <param name="rawString"></param>
 3223      public ZipString(byte[] rawString)
 3224      {
 3225        rawComment_ = rawString;
 3226      }
 3227      #endregion
 3228
 3229      /// <summary>
 3230      /// Get a value indicating the original source of data for this instance.
 3231      /// True if the source was a string; false if the source was binary data.
 3232      /// </summary>
 3233      public bool IsSourceString {
 3234        get { return isSourceString_; }
 3235      }
 3236
 3237      /// <summary>
 3238      /// Get the length of the comment when represented as raw bytes.
 3239      /// </summary>
 3240      public int RawLength {
 3241        get {
 3242          MakeBytesAvailable();
 3243          return rawComment_.Length;
 3244        }
 3245      }
 3246
 3247      /// <summary>
 3248      /// Get the comment in its 'raw' form as plain bytes.
 3249      /// </summary>
 3250      public byte[] RawComment {
 3251        get {
 3252          MakeBytesAvailable();
 3253          return (byte[])rawComment_.Clone();
 3254        }
 3255      }
 3256
 3257      /// <summary>
 3258      /// Reset the comment to its initial state.
 3259      /// </summary>
 3260      public void Reset()
 3261      {
 3262        if (isSourceString_) {
 3263          rawComment_ = null;
 3264        } else {
 3265          comment_ = null;
 3266        }
 3267      }
 3268
 3269      void MakeTextAvailable()
 3270      {
 3271        if (comment_ == null) {
 3272          comment_ = ZipConstants.ConvertToString(rawComment_);
 3273        }
 3274      }
 3275
 3276      void MakeBytesAvailable()
 3277      {
 3278        if (rawComment_ == null) {
 3279          rawComment_ = ZipConstants.ConvertToArray(comment_);
 3280        }
 3281      }
 3282
 3283      /// <summary>
 3284      /// Implicit conversion of comment to a string.
 3285      /// </summary>
 3286      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>
 3287      /// <returns>The textual equivalent for the input value.</returns>
 3288      static public implicit operator string(ZipString zipString)
 3289      {
 3290        zipString.MakeTextAvailable();
 3291        return zipString.comment_;
 3292      }
 3293
 3294      #region Instance Fields
 3295      string comment_;
 3296      byte[] rawComment_;
 3297      bool isSourceString_;
 3298      #endregion
 3299    }
 3300
 3301    /// <summary>
 3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>
 3303    /// </summary>
 3304    class ZipEntryEnumerator : IEnumerator
 3305    {
 3306      #region Constructors
 3307      public ZipEntryEnumerator(ZipEntry[] entries)
 3308      {
 3309        array = entries;
 3310      }
 3311
 3312      #endregion
 3313      #region IEnumerator Members
 3314      public object Current {
 3315        get {
 3316          return array[index];
 3317        }
 3318      }
 3319
 3320      public void Reset()
 3321      {
 3322        index = -1;
 3323      }
 3324
 3325      public bool MoveNext()
 3326      {
 3327        return (++index < array.Length);
 3328      }
 3329      #endregion
 3330      #region Instance Fields
 3331      ZipEntry[] array;
 3332      int index = -1;
 3333      #endregion
 3334    }
 3335
 3336    /// <summary>
 3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data
 3338    /// to and flush, but cannot read, seek or do anything else to.
 3339    /// </summary>
 3340    class UncompressedStream : Stream
 3341    {
 3342      #region Constructors
 3343      public UncompressedStream(Stream baseStream)
 3344      {
 3345        baseStream_ = baseStream;
 3346      }
 3347
 3348      #endregion
 3349
 3350      /// <summary>
 3351      /// Close this stream instance.
 3352      /// </summary>
 3353      public override void Close()
 3354      {
 3355        // Do nothing
 3356      }
 3357
 3358      /// <summary>
 3359      /// Gets a value indicating whether the current stream supports reading.
 3360      /// </summary>
 3361      public override bool CanRead {
 3362        get {
 3363          return false;
 3364        }
 3365      }
 3366
 3367      /// <summary>
 3368      /// Write any buffered data to underlying storage.
 3369      /// </summary>
 3370      public override void Flush()
 3371      {
 3372        baseStream_.Flush();
 3373      }
 3374
 3375      /// <summary>
 3376      /// Gets a value indicating whether the current stream supports writing.
 3377      /// </summary>
 3378      public override bool CanWrite {
 3379        get {
 3380          return baseStream_.CanWrite;
 3381        }
 3382      }
 3383
 3384      /// <summary>
 3385      /// Gets a value indicating whether the current stream supports seeking.
 3386      /// </summary>
 3387      public override bool CanSeek {
 3388        get {
 3389          return false;
 3390        }
 3391      }
 3392
 3393      /// <summary>
 3394      /// Get the length in bytes of the stream.
 3395      /// </summary>
 3396      public override long Length {
 3397        get {
 3398          return 0;
 3399        }
 3400      }
 3401
 3402      /// <summary>
 3403      /// Gets or sets the position within the current stream.
 3404      /// </summary>
 3405      public override long Position {
 3406        get {
 3407          return baseStream_.Position;
 3408        }
 3409        set {
 3410          throw new NotImplementedException();
 3411        }
 3412      }
 3413
 3414      /// <summary>
 3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3416      /// </summary>
 3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3419      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3420      /// <returns>
 3421      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3422      /// </returns>
 3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3425      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3426      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3427      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3428      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3429      public override int Read(byte[] buffer, int offset, int count)
 3430      {
 3431        return 0;
 3432      }
 3433
 3434      /// <summary>
 3435      /// Sets the position within the current stream.
 3436      /// </summary>
 3437      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3438      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3439      /// <returns>
 3440      /// The new position within the current stream.
 3441      /// </returns>
 3442      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3443      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3445      public override long Seek(long offset, SeekOrigin origin)
 3446      {
 3447        return 0;
 3448      }
 3449
 3450      /// <summary>
 3451      /// Sets the length of the current stream.
 3452      /// </summary>
 3453      /// <param name="value">The desired length of the current stream in bytes.</param>
 3454      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3455      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3456      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3457      public override void SetLength(long value)
 3458      {
 3459      }
 3460
 3461      /// <summary>
 3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3463      /// </summary>
 3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3466      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3467      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3468      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3469      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3470      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3471      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3472      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3473      public override void Write(byte[] buffer, int offset, int count)
 3474      {
 3475        baseStream_.Write(buffer, offset, count);
 3476      }
 3477
 3478      readonly
 3479
 3480      #region Instance Fields
 3481      Stream baseStream_;
 3482      #endregion
 3483    }
 3484
 3485    /// <summary>
 3486    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>
 3487    /// whose data is only a part or subsection of a file.
 3488    /// </summary>
 3489    class PartialInputStream : Stream
 3490    {
 3491      #region Constructors
 3492      /// <summary>
 3493      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.
 3494      /// </summary>
 3495      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>
 3496      /// <param name="start">The start of the partial data.</param>
 3497      /// <param name="length">The length of the partial data.</param>
 3498      public PartialInputStream(ZipFile zipFile, long start, long length)
 3499      {
 3500        start_ = start;
 3501        length_ = length;
 3502
 3503        // Although this is the only time the zipfile is used
 3504        // keeping a reference here prevents premature closure of
 3505        // this zip file and thus the baseStream_.
 3506
 3507        // Code like this will cause apparently random failures depending
 3508        // on the size of the files and when garbage is collected.
 3509        //
 3510        // ZipFile z = new ZipFile (stream);
 3511        // Stream reader = z.GetInputStream(0);
 3512        // uses reader here....
 3513        zipFile_ = zipFile;
 3514        baseStream_ = zipFile_.baseStream_;
 3515        readPos_ = start;
 3516        end_ = start + length;
 3517      }
 3518      #endregion
 3519
 3520      /// <summary>
 3521      /// Read a byte from this stream.
 3522      /// </summary>
 3523      /// <returns>Returns the byte read or -1 on end of stream.</returns>
 3524      public override int ReadByte()
 3525      {
 3526        if (readPos_ >= end_) {
 3527          // -1 is the correct value at end of stream.
 3528          return -1;
 3529        }
 3530
 3531        lock (baseStream_) {
 3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);
 3533          return baseStream_.ReadByte();
 3534        }
 3535      }
 3536
 3537      /// <summary>
 3538      /// Close this <see cref="PartialInputStream">partial input stream</see>.
 3539      /// </summary>
 3540      /// <remarks>
 3541      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.
 3542      /// </remarks>
 3543      public override void Close()
 3544      {
 3545        // Do nothing at all!
 3546      }
 3547
 3548      /// <summary>
 3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3550      /// </summary>
 3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3553      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3554      /// <returns>
 3555      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3556      /// </returns>
 3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3559      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3560      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3561      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3562      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3563      public override int Read(byte[] buffer, int offset, int count)
 3564      {
 3565        lock (baseStream_) {
 3566          if (count > end_ - readPos_) {
 3567            count = (int)(end_ - readPos_);
 3568            if (count == 0) {
 3569              return 0;
 3570            }
 3571          }
 3572          // Protect against Stream implementations that throw away their buffer on every Seek
 3573          // (for example, Mono FileStream)
 3574          if (baseStream_.Position != readPos_) {
 3575            baseStream_.Seek(readPos_, SeekOrigin.Begin);
 3576          }
 3577          int readCount = baseStream_.Read(buffer, offset, count);
 3578          if (readCount > 0) {
 3579            readPos_ += readCount;
 3580          }
 3581          return readCount;
 3582        }
 3583      }
 3584
 3585      /// <summary>
 3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3587      /// </summary>
 3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3590      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3591      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3592      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3593      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3594      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3595      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3596      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3597      public override void Write(byte[] buffer, int offset, int count)
 3598      {
 3599        throw new NotSupportedException();
 3600      }
 3601
 3602      /// <summary>
 3603      /// When overridden in a derived class, sets the length of the current stream.
 3604      /// </summary>
 3605      /// <param name="value">The desired length of the current stream in bytes.</param>
 3606      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3607      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3608      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3609      public override void SetLength(long value)
 3610      {
 3611        throw new NotSupportedException();
 3612      }
 3613
 3614      /// <summary>
 3615      /// When overridden in a derived class, sets the position within the current stream.
 3616      /// </summary>
 3617      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3618      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3619      /// <returns>
 3620      /// The new position within the current stream.
 3621      /// </returns>
 3622      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3623      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3625      public override long Seek(long offset, SeekOrigin origin)
 3626      {
 3627        long newPos = readPos_;
 3628
 3629        switch (origin) {
 3630          case SeekOrigin.Begin:
 3631            newPos = start_ + offset;
 3632            break;
 3633
 3634          case SeekOrigin.Current:
 3635            newPos = readPos_ + offset;
 3636            break;
 3637
 3638          case SeekOrigin.End:
 3639            newPos = end_ + offset;
 3640            break;
 3641        }
 3642
 3643        if (newPos < start_) {
 3644          throw new ArgumentException("Negative position is invalid");
 3645        }
 3646
 3647        if (newPos >= end_) {
 3648          throw new IOException("Cannot seek past end");
 3649        }
 3650        readPos_ = newPos;
 3651        return readPos_;
 3652      }
 3653
 3654      /// <summary>
 3655      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
 3656      /// </summary>
 3657      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3658      public override void Flush()
 3659      {
 3660        // Nothing to do.
 3661      }
 3662
 3663      /// <summary>
 3664      /// Gets or sets the position within the current stream.
 3665      /// </summary>
 3666      /// <value></value>
 3667      /// <returns>The current position within the stream.</returns>
 3668      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3669      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>
 3670      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3671      public override long Position {
 3672        get { return readPos_ - start_; }
 3673        set {
 3674          long newPos = start_ + value;
 3675
 3676          if (newPos < start_) {
 3677            throw new ArgumentException("Negative position is invalid");
 3678          }
 3679
 3680          if (newPos >= end_) {
 3681            throw new InvalidOperationException("Cannot seek past end");
 3682          }
 3683          readPos_ = newPos;
 3684        }
 3685      }
 3686
 3687      /// <summary>
 3688      /// Gets the length in bytes of the stream.
 3689      /// </summary>
 3690      /// <value></value>
 3691      /// <returns>A long value representing the length of the stream in bytes.</returns>
 3692      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep
 3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3694      public override long Length {
 3695        get { return length_; }
 3696      }
 3697
 3698      /// <summary>
 3699      /// Gets a value indicating whether the current stream supports writing.
 3700      /// </summary>
 3701      /// <value>false</value>
 3702      /// <returns>true if the stream supports writing; otherwise, false.</returns>
 3703      public override bool CanWrite {
 3704        get { return false; }
 3705      }
 3706
 3707      /// <summary>
 3708      /// Gets a value indicating whether the current stream supports seeking.
 3709      /// </summary>
 3710      /// <value>true</value>
 3711      /// <returns>true if the stream supports seeking; otherwise, false.</returns>
 3712      public override bool CanSeek {
 3713        get { return true; }
 3714      }
 3715
 3716      /// <summary>
 3717      /// Gets a value indicating whether the current stream supports reading.
 3718      /// </summary>
 3719      /// <value>true.</value>
 3720      /// <returns>true if the stream supports reading; otherwise, false.</returns>
 3721      public override bool CanRead {
 3722        get { return true; }
 3723      }
 3724
 3725      /// <summary>
 3726      /// Gets a value that determines whether the current stream can time out.
 3727      /// </summary>
 3728      /// <value></value>
 3729      /// <returns>A value that determines whether the current stream can time out.</returns>
 3730      public override bool CanTimeout {
 3731        get { return baseStream_.CanTimeout; }
 3732      }
 3733      #region Instance Fields
 3734      ZipFile zipFile_;
 3735      Stream baseStream_;
 3736      long start_;
 3737      long length_;
 3738      long readPos_;
 3739      long end_;
 3740      #endregion
 3741    }
 3742    #endregion
 3743  }
 3744
 3745  #endregion
 3746
 3747  #region DataSources
 3748  /// <summary>
 3749  /// Provides a static way to obtain a source of data for an entry.
 3750  /// </summary>
 3751  public interface IStaticDataSource
 3752  {
 3753    /// <summary>
 3754    /// Get a source of data by creating a new stream.
 3755    /// </summary>
 3756    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3757    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3758    Stream GetSource();
 3759  }
 3760
 3761  /// <summary>
 3762  /// Represents a source of data that can dynamically provide
 3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.
 3764  /// </summary>
 3765  public interface IDynamicDataSource
 3766  {
 3767    /// <summary>
 3768    /// Get a data source.
 3769    /// </summary>
 3770    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>
 3771    /// <param name="name">The name for data if known.</param>
 3772    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3773    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3774    Stream GetSource(ZipEntry entry, string name);
 3775  }
 3776
 3777  /// <summary>
 3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.
 3779  /// </summary>
 3780  public class StaticDiskDataSource : IStaticDataSource
 3781  {
 3782    /// <summary>
 3783    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>
 3784    /// </summary>
 3785    /// <param name="fileName">The name of the file to obtain data from.</param>
 3786    public StaticDiskDataSource(string fileName)
 3787    {
 3788      fileName_ = fileName;
 3789    }
 3790
 3791    #region IDataSource Members
 3792
 3793    /// <summary>
 3794    /// Get a <see cref="Stream"/> providing data.
 3795    /// </summary>
 3796    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>
 3797    public Stream GetSource()
 3798    {
 3799      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 3800    }
 3801
 3802    readonly
 3803
 3804    #endregion
 3805    #region Instance Fields
 3806    string fileName_;
 3807    #endregion
 3808  }
 3809
 3810
 3811  /// <summary>
 3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.
 3813  /// </summary>
 3814  public class DynamicDiskDataSource : IDynamicDataSource
 3815  {
 3816
 3817    #region IDataSource Members
 3818    /// <summary>
 3819    /// Get a <see cref="Stream"/> providing data for an entry.
 3820    /// </summary>
 3821    /// <param name="entry">The entry to provide data for.</param>
 3822    /// <param name="name">The file name for data if known.</param>
 3823    /// <returns>Returns a stream providing data; or null if not available</returns>
 3824    public Stream GetSource(ZipEntry entry, string name)
 3825    {
 3826      Stream result = null;
 3827
 3828      if (name != null) {
 3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 3830      }
 3831
 3832      return result;
 3833    }
 3834
 3835    #endregion
 3836  }
 3837
 3838  #endregion
 3839
 3840  #region Archive Storage
 3841  /// <summary>
 3842  /// Defines facilities for data storage when updating Zip Archives.
 3843  /// </summary>
 3844  public interface IArchiveStorage
 3845  {
 3846    /// <summary>
 3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.
 3848    /// </summary>
 3849    FileUpdateMode UpdateMode { get; }
 3850
 3851    /// <summary>
 3852    /// Get an empty <see cref="Stream"/> that can be used for temporary output.
 3853    /// </summary>
 3854    /// <returns>Returns a temporary output <see cref="Stream"/></returns>
 3855    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3856    Stream GetTemporaryOutput();
 3857
 3858    /// <summary>
 3859    /// Convert a temporary output stream to a final stream.
 3860    /// </summary>
 3861    /// <returns>The resulting final <see cref="Stream"/></returns>
 3862    /// <seealso cref="GetTemporaryOutput"/>
 3863    Stream ConvertTemporaryToFinal();
 3864
 3865    /// <summary>
 3866    /// Make a temporary copy of the original stream.
 3867    /// </summary>
 3868    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 3869    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3870    Stream MakeTemporaryCopy(Stream stream);
 3871
 3872    /// <summary>
 3873    /// Return a stream suitable for performing direct updates on the original source.
 3874    /// </summary>
 3875    /// <param name="stream">The current stream.</param>
 3876    /// <returns>Returns a stream suitable for direct updating.</returns>
 3877    /// <remarks>This may be the current stream passed.</remarks>
 3878    Stream OpenForDirectUpdate(Stream stream);
 3879
 3880    /// <summary>
 3881    /// Dispose of this instance.
 3882    /// </summary>
 3883    void Dispose();
 3884  }
 3885
 3886  /// <summary>
 3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.
 3888  /// </summary>
 3889  abstract public class BaseArchiveStorage : IArchiveStorage
 3890  {
 3891    #region Constructors
 3892    /// <summary>
 3893    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.
 3894    /// </summary>
 3895    /// <param name="updateMode">The update mode.</param>
 3896    protected BaseArchiveStorage(FileUpdateMode updateMode)
 3897    {
 3898      updateMode_ = updateMode;
 3899    }
 3900    #endregion
 3901
 3902    #region IArchiveStorage Members
 3903
 3904    /// <summary>
 3905    /// Gets a temporary output <see cref="Stream"/>
 3906    /// </summary>
 3907    /// <returns>Returns the temporary output stream.</returns>
 3908    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3909    public abstract Stream GetTemporaryOutput();
 3910
 3911    /// <summary>
 3912    /// Converts the temporary <see cref="Stream"/> to its final form.
 3913    /// </summary>
 3914    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 3915    /// the final storage for the archive.</returns>
 3916    /// <seealso cref="GetTemporaryOutput"/>
 3917    public abstract Stream ConvertTemporaryToFinal();
 3918
 3919    /// <summary>
 3920    /// Make a temporary copy of a <see cref="Stream"/>.
 3921    /// </summary>
 3922    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>
 3923    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3924    public abstract Stream MakeTemporaryCopy(Stream stream);
 3925
 3926    /// <summary>
 3927    /// Return a stream suitable for performing direct updates on the original source.
 3928    /// </summary>
 3929    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>
 3930    /// <returns>Returns a stream suitable for direct updating.</returns>
 3931    public abstract Stream OpenForDirectUpdate(Stream stream);
 3932
 3933    /// <summary>
 3934    /// Disposes this instance.
 3935    /// </summary>
 3936    public abstract void Dispose();
 3937
 3938    /// <summary>
 3939    /// Gets the update mode applicable.
 3940    /// </summary>
 3941    /// <value>The update mode.</value>
 3942    public FileUpdateMode UpdateMode {
 3943      get {
 3944        return updateMode_;
 3945      }
 3946    }
 3947
 3948    #endregion
 3949
 3950    #region Instance Fields
 3951    FileUpdateMode updateMode_;
 3952    #endregion
 3953  }
 3954
 3955  /// <summary>
 3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.
 3957  /// </summary>
 3958  public class DiskArchiveStorage : BaseArchiveStorage
 3959  {
 3960    #region Constructors
 3961    /// <summary>
 3962    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3963    /// </summary>
 3964    /// <param name="file">The file.</param>
 3965    /// <param name="updateMode">The update mode.</param>
 3966    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)
 3967      : base(updateMode)
 3968    {
 3969      if (file.Name == null) {
 3970        throw new ZipException("Cant handle non file archives");
 3971      }
 3972
 3973      fileName_ = file.Name;
 3974    }
 3975
 3976    /// <summary>
 3977    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3978    /// </summary>
 3979    /// <param name="file">The file.</param>
 3980    public DiskArchiveStorage(ZipFile file)
 3981      : this(file, FileUpdateMode.Safe)
 3982    {
 3983    }
 3984    #endregion
 3985
 3986    #region IArchiveStorage Members
 3987
 3988    /// <summary>
 3989    /// Gets a temporary output <see cref="Stream"/> for performing updates on.
 3990    /// </summary>
 3991    /// <returns>Returns the temporary output stream.</returns>
 3992    public override Stream GetTemporaryOutput()
 3993    {
 3994      if (temporaryName_ != null) {
 3995        temporaryName_ = GetTempFileName(temporaryName_, true);
 3996        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 3997      } else {
 3998        // Determine where to place files based on internal strategy.
 3999        // Currently this is always done in system temp directory.
 4000        temporaryName_ = Path.GetTempFileName();
 4001        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 4002      }
 4003
 4004      return temporaryStream_;
 4005    }
 4006
 4007    /// <summary>
 4008    /// Converts a temporary <see cref="Stream"/> to its final form.
 4009    /// </summary>
 4010    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4011    /// the final storage for the archive.</returns>
 4012    public override Stream ConvertTemporaryToFinal()
 4013    {
 4014      if (temporaryStream_ == null) {
 4015        throw new ZipException("No temporary stream has been created");
 4016      }
 4017
 4018      Stream result = null;
 4019
 4020      string moveTempName = GetTempFileName(fileName_, false);
 4021      bool newFileCreated = false;
 4022
 4023      try {
 4024        temporaryStream_.Close();
 4025        File.Move(fileName_, moveTempName);
 4026        File.Move(temporaryName_, fileName_);
 4027        newFileCreated = true;
 4028        File.Delete(moveTempName);
 4029
 4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 4031      } catch (Exception) {
 4032        result = null;
 4033
 4034        // Try to roll back changes...
 4035        if (!newFileCreated) {
 4036          File.Move(moveTempName, fileName_);
 4037          File.Delete(temporaryName_);
 4038        }
 4039
 4040        throw;
 4041      }
 4042
 4043      return result;
 4044    }
 4045
 4046    /// <summary>
 4047    /// Make a temporary copy of a stream.
 4048    /// </summary>
 4049    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4050    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4051    public override Stream MakeTemporaryCopy(Stream stream)
 4052    {
 4053      stream.Close();
 4054
 4055      temporaryName_ = GetTempFileName(fileName_, true);
 4056      File.Copy(fileName_, temporaryName_, true);
 4057
 4058      temporaryStream_ = new FileStream(temporaryName_,
 4059        FileMode.Open,
 4060        FileAccess.ReadWrite);
 4061      return temporaryStream_;
 4062    }
 4063
 4064    /// <summary>
 4065    /// Return a stream suitable for performing direct updates on the original source.
 4066    /// </summary>
 4067    /// <param name="stream">The current stream.</param>
 4068    /// <returns>Returns a stream suitable for direct updating.</returns>
 4069    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>
 4070    public override Stream OpenForDirectUpdate(Stream stream)
 4071    {
 4072      Stream result;
 4073      if ((stream == null) || !stream.CanWrite) {
 4074        if (stream != null) {
 4075          stream.Close();
 4076        }
 4077
 4078        result = new FileStream(fileName_,
 4079            FileMode.Open,
 4080            FileAccess.ReadWrite);
 4081      } else {
 4082        result = stream;
 4083      }
 4084
 4085      return result;
 4086    }
 4087
 4088    /// <summary>
 4089    /// Disposes this instance.
 4090    /// </summary>
 4091    public override void Dispose()
 4092    {
 4093      if (temporaryStream_ != null) {
 4094        temporaryStream_.Close();
 4095      }
 4096    }
 4097
 4098    #endregion
 4099
 4100    #region Internal routines
 4101    static string GetTempFileName(string original, bool makeTempFile)
 4102    {
 4103      string result = null;
 4104
 4105      if (original == null) {
 4106        result = Path.GetTempFileName();
 4107      } else {
 4108        int counter = 0;
 4109        int suffixSeed = DateTime.Now.Second;
 4110
 4111        while (result == null) {
 4112          counter += 1;
 4113          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);
 4114          if (!File.Exists(newName)) {
 4115            if (makeTempFile) {
 4116              try {
 4117                // Try and create the file.
 4118                using (FileStream stream = File.Create(newName)) {
 4119                }
 4120                result = newName;
 4121              } catch {
 4122                suffixSeed = DateTime.Now.Second;
 4123              }
 4124            } else {
 4125              result = newName;
 4126            }
 4127          }
 4128        }
 4129      }
 4130      return result;
 4131    }
 4132    #endregion
 4133
 4134    #region Instance Fields
 4135    Stream temporaryStream_;
 4136    string fileName_;
 4137    string temporaryName_;
 4138    #endregion
 4139  }
 4140
 4141  /// <summary>
 4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.
 4143  /// </summary>
 4144  public class MemoryArchiveStorage : BaseArchiveStorage
 4145  {
 4146    #region Constructors
 4147    /// <summary>
 4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4149    /// </summary>
 4150    public MemoryArchiveStorage()
 4151      : base(FileUpdateMode.Direct)
 4152    {
 4153    }
 4154
 4155    /// <summary>
 4156    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4157    /// </summary>
 4158    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>
 4159    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>
 4160    public MemoryArchiveStorage(FileUpdateMode updateMode)
 4161      : base(updateMode)
 4162    {
 4163    }
 4164
 4165    #endregion
 4166
 4167    #region Properties
 4168    /// <summary>
 4169    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.
 4170    /// </summary>
 4171    public MemoryStream FinalStream {
 4172      get { return finalStream_; }
 4173    }
 4174
 4175    #endregion
 4176
 4177    #region IArchiveStorage Members
 4178
 4179    /// <summary>
 4180    /// Gets the temporary output <see cref="Stream"/>
 4181    /// </summary>
 4182    /// <returns>Returns the temporary output stream.</returns>
 4183    public override Stream GetTemporaryOutput()
 4184    {
 4185      temporaryStream_ = new MemoryStream();
 4186      return temporaryStream_;
 4187    }
 4188
 4189    /// <summary>
 4190    /// Converts the temporary <see cref="Stream"/> to its final form.
 4191    /// </summary>
 4192    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4193    /// the final storage for the archive.</returns>
 4194    public override Stream ConvertTemporaryToFinal()
 4195    {
 4196      if (temporaryStream_ == null) {
 4197        throw new ZipException("No temporary stream has been created");
 4198      }
 4199
 4200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());
 4201      return finalStream_;
 4202    }
 4203
 4204    /// <summary>
 4205    /// Make a temporary copy of the original stream.
 4206    /// </summary>
 4207    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4208    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4209    public override Stream MakeTemporaryCopy(Stream stream)
 4210    {
 4211      temporaryStream_ = new MemoryStream();
 4212      stream.Position = 0;
 4213      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);
 4214      return temporaryStream_;
 4215    }
 4216
 4217    /// <summary>
 4218    /// Return a stream suitable for performing direct updates on the original source.
 4219    /// </summary>
 4220    /// <param name="stream">The original source stream</param>
 4221    /// <returns>Returns a stream suitable for direct updating.</returns>
 4222    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;
 4223    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>
 4224    public override Stream OpenForDirectUpdate(Stream stream)
 4225    {
 4226      Stream result;
 4227      if ((stream == null) || !stream.CanWrite) {
 4228
 4229        result = new MemoryStream();
 4230
 4231        if (stream != null) {
 4232          stream.Position = 0;
 4233          StreamUtils.Copy(stream, result, new byte[4096]);
 4234
 4235          stream.Close();
 4236        }
 4237      } else {
 4238        result = stream;
 4239      }
 4240
 4241      return result;
 4242    }
 4243
 4244    /// <summary>
 4245    /// Disposes this instance.
 4246    /// </summary>
 4247    public override void Dispose()
 4248    {
 4249      if (temporaryStream_ != null) {
 4250        temporaryStream_.Close();
 4251      }
 4252    }
 4253
 4254    #endregion
 4255
 4256    #region Instance Fields
 4257    MemoryStream temporaryStream_;
 4258    MemoryStream finalStream_;
 4259    #endregion
 4260  }
 4261
 4262  #endregion
 4263}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_WindowsNameTransform.htm b/docs/opencover/ICSharpCode.SharpZipLib_WindowsNameTransform.htm new file mode 100644 index 000000000..ff2ab33ca --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_WindowsNameTransform.htm @@ -0,0 +1,274 @@ + + + + +ICSharpCode.SharpZipLib.Zip.WindowsNameTransform - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.WindowsNameTransform
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\WindowsNameTransform.cs
Covered lines:42
Uncovered lines:35
Coverable lines:77
Total lines:226
Line coverage:54.5%
Branch coverage:42.8%
+

Metrics

+ + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)283.3366.67
.ctor()1100100
TransformDirectory(...)371.4360
TransformFile(...)477.7871.43
IsValidName(...)300
.cctor()1100100
MakeValidName(...)115052.38
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\WindowsNameTransform.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Text;
 4using ICSharpCode.SharpZipLib.Core;
 5
 6namespace ICSharpCode.SharpZipLib.Zip
 7{
 8  /// <summary>
 9  /// WindowsNameTransform transforms <see cref="ZipFile"/> names to windows compatible ones.
 10  /// </summary>
 11  public class WindowsNameTransform : INameTransform
 12  {
 13    /// <summary>
 14    /// Initialises a new instance of <see cref="WindowsNameTransform"/>
 15    /// </summary>
 16    /// <param name="baseDirectory"></param>
 117    public WindowsNameTransform(string baseDirectory)
 18    {
 119       if (baseDirectory == null) {
 020        throw new ArgumentNullException(nameof(baseDirectory), "Directory name is invalid");
 21      }
 22
 123      BaseDirectory = baseDirectory;
 124    }
 25
 26    /// <summary>
 27    /// Initialise a default instance of <see cref="WindowsNameTransform"/>
 28    /// </summary>
 229    public WindowsNameTransform()
 30    {
 31      // Do nothing.
 232    }
 33
 34    /// <summary>
 35    /// Gets or sets a value containing the target directory to prefix values with.
 36    /// </summary>
 37    public string BaseDirectory {
 038      get { return _baseDirectory; }
 39      set {
 140         if (value == null) {
 041          throw new ArgumentNullException(nameof(value));
 42        }
 43
 144        _baseDirectory = Path.GetFullPath(value);
 145      }
 46    }
 47
 48    /// <summary>
 49    /// Gets or sets a value indicating wether paths on incoming values should be removed.
 50    /// </summary>
 51    public bool TrimIncomingPaths {
 052      get { return _trimIncomingPaths; }
 053      set { _trimIncomingPaths = value; }
 54    }
 55
 56    /// <summary>
 57    /// Transform a Zip directory name to a windows directory name.
 58    /// </summary>
 59    /// <param name="name">The directory name to transform.</param>
 60    /// <returns>The transformed name.</returns>
 61    public string TransformDirectory(string name)
 62    {
 363      name = TransformFile(name);
 264       if (name.Length > 0) {
 265         while (name.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) {
 066          name = name.Remove(name.Length - 1, 1);
 67        }
 268      } else {
 069        throw new ZipException("Cannot have an empty directory name");
 70      }
 271      return name;
 72    }
 73
 74    /// <summary>
 75    /// Transform a Zip format file name to a windows style one.
 76    /// </summary>
 77    /// <param name="name">The file name to transform.</param>
 78    /// <returns>The transformed name.</returns>
 79    public string TransformFile(string name)
 80    {
 381       if (name != null) {
 382        name = MakeValidName(name, _replacementChar);
 83
 284         if (_trimIncomingPaths) {
 085          name = Path.GetFileName(name);
 86        }
 87
 88        // This may exceed windows length restrictions.
 89        // Combine will throw a PathTooLongException in that case.
 290         if (_baseDirectory != null) {
 191          name = Path.Combine(_baseDirectory, name);
 92        }
 193      } else {
 094        name = string.Empty;
 95      }
 296      return name;
 97    }
 98
 99    /// <summary>
 100    /// Test a name to see if it is a valid name for a windows filename as extracted from a Zip archive.
 101    /// </summary>
 102    /// <param name="name">The name to test.</param>
 103    /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
 104    /// <remarks>The filename isnt a true windows path in some fundamental ways like no absolute paths, no rooted paths 
 105    public static bool IsValidName(string name)
 106    {
 0107      bool result =
 0108        (name != null) &&
 0109        (name.Length <= MaxPath) &&
 0110        (string.Compare(name, MakeValidName(name, '_'), StringComparison.Ordinal) == 0)
 0111        ;
 112
 0113      return result;
 114    }
 115
 116    /// <summary>
 117    /// Initialise static class information.
 118    /// </summary>
 119    static WindowsNameTransform()
 120    {
 121      char[] invalidPathChars;
 122
 1123      invalidPathChars = Path.GetInvalidPathChars();
 1124      int howMany = invalidPathChars.Length + 3;
 125
 1126      InvalidEntryChars = new char[howMany];
 1127      Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length);
 1128      InvalidEntryChars[howMany - 1] = '*';
 1129      InvalidEntryChars[howMany - 2] = '?';
 1130      InvalidEntryChars[howMany - 3] = ':';
 1131    }
 132
 133    /// <summary>
 134    /// Force a name to be valid by replacing invalid characters with a fixed value
 135    /// </summary>
 136    /// <param name="name">The name to make valid</param>
 137    /// <param name="replacement">The replacement character to use for any invalid characters.</param>
 138    /// <returns>Returns a valid name</returns>
 139    public static string MakeValidName(string name, char replacement)
 140    {
 3141       if (name == null) {
 0142        throw new ArgumentNullException(nameof(name));
 143      }
 144
 3145      name = WindowsPathUtils.DropPathRoot(name.Replace("/", Path.DirectorySeparatorChar.ToString()));
 146
 147      // Drop any leading slashes.
 3148       while ((name.Length > 0) && (name[0] == Path.DirectorySeparatorChar)) {
 0149        name = name.Remove(0, 1);
 150      }
 151
 152      // Drop any trailing slashes.
 4153       while ((name.Length > 0) && (name[name.Length - 1] == Path.DirectorySeparatorChar)) {
 1154        name = name.Remove(name.Length - 1, 1);
 155      }
 156
 157      // Convert consecutive \\ characters to \
 3158      int index = name.IndexOf(string.Format("{0}{0}", Path.DirectorySeparatorChar), StringComparison.Ordinal);
 3159       while (index >= 0) {
 0160        name = name.Remove(index, 1);
 0161        index = name.IndexOf(Path.DirectorySeparatorChar);
 162      }
 163
 164      // Convert any invalid characters using the replacement one.
 3165      index = name.IndexOfAny(InvalidEntryChars);
 3166       if (index >= 0) {
 0167        var builder = new StringBuilder(name);
 168
 0169         while (index >= 0) {
 0170          builder[index] = replacement;
 171
 0172           if (index >= name.Length) {
 0173            index = -1;
 0174          } else {
 0175            index = name.IndexOfAny(InvalidEntryChars, index + 1);
 176          }
 177        }
 0178        name = builder.ToString();
 179      }
 180
 181      // Check for names greater than MaxPath characters.
 182      // TODO: Were is CLR version of MaxPath defined?  Can't find it in Environment.
 3183       if (name.Length > MaxPath) {
 1184        throw new PathTooLongException();
 185      }
 186
 2187      return name;
 188    }
 189
 190    /// <summary>
 191    /// Gets or set the character to replace invalid characters during transformations.
 192    /// </summary>
 193    public char Replacement {
 0194      get { return _replacementChar; }
 195      set {
 0196         for (int i = 0; i < InvalidEntryChars.Length; ++i) {
 0197           if (InvalidEntryChars[i] == value) {
 0198            throw new ArgumentException("invalid path character");
 199          }
 200        }
 201
 0202         if ((value == Path.DirectorySeparatorChar) || (value == Path.AltDirectorySeparatorChar)) {
 0203          throw new ArgumentException("invalid replacement character");
 204        }
 205
 0206        _replacementChar = value;
 0207      }
 208    }
 209
 210    /// <summary>
 211    ///  The maximum windows path name permitted.
 212    /// </summary>
 213    /// <remarks>This may not valid for all windows systems - CE?, etc but I cant find the equivalent in the CLR.</remar
 214    const int MaxPath = 260;
 215
 216    #region Instance Fields
 217    string _baseDirectory;
 218    bool _trimIncomingPaths;
 3219    char _replacementChar = '_';
 220    #endregion
 221
 222    #region Class Fields
 223    static readonly char[] InvalidEntryChars;
 224    #endregion
 225  }
 226}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_WindowsPathUtils.htm b/docs/opencover/ICSharpCode.SharpZipLib_WindowsPathUtils.htm new file mode 100644 index 000000000..28022755e --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_WindowsPathUtils.htm @@ -0,0 +1,100 @@ + + + + +ICSharpCode.SharpZipLib.Core.WindowsPathUtils - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Core.WindowsPathUtils
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\WindowsPathUtils.cs
Covered lines:19
Uncovered lines:3
Coverable lines:22
Total lines:57
Line coverage:86.3%
Branch coverage:76.6%
+

Metrics

+ + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()100
DropPathRoot(...)179077.42
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Core\WindowsPathUtils.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1namespace ICSharpCode.SharpZipLib.Core
 2{
 3  /// <summary>
 4  /// WindowsPathUtils provides simple utilities for handling windows paths.
 5  /// </summary>
 6  public abstract class WindowsPathUtils
 7  {
 8    /// <summary>
 9    /// Initializes a new instance of the <see cref="WindowsPathUtils"/> class.
 10    /// </summary>
 011    internal WindowsPathUtils()
 12    {
 013    }
 14
 15    /// <summary>
 16    /// Remove any path root present in the path
 17    /// </summary>
 18    /// <param name="path">A <see cref="string"/> containing path information.</param>
 19    /// <returns>The path with the root removed if it was present; path otherwise.</returns>
 20    /// <remarks>Unlike the <see cref="System.IO.Path"/> class the path isnt otherwise checked for validity.</remarks>
 21    public static string DropPathRoot(string path)
 22    {
 6593023      string result = path;
 24
 6593025       if (!string.IsNullOrEmpty(path)) {
 6593026         if ((path[0] == '\\') || (path[0] == '/')) {
 27          // UNC name ?
 628           if ((path.Length > 1) && ((path[1] == '\\') || (path[1] == '/'))) {
 129            int index = 2;
 130            int elements = 2;
 31
 32            // Scan for two separate elements \\machine\share\restofpath
 1133             while ((index <= path.Length) &&
 1134              (((path[index] != '\\') && (path[index] != '/')) || (--elements > 0))) {
 1035              index++;
 36            }
 37
 138            index++;
 39
 140             if (index < path.Length) {
 141              result = path.Substring(index);
 142            } else {
 043              result = "";
 44            }
 45          }
 6592446         } else if ((path.Length > 1) && (path[1] == ':')) {
 1047          int dropCount = 2;
 1048           if ((path.Length > 2) && ((path[2] == '\\') || (path[2] == '/'))) {
 949            dropCount = 3;
 50          }
 1051          result = result.Remove(0, dropCount);
 52        }
 53      }
 6593054      return result;
 55    }
 56  }
 57}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipAESStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipAESStream.htm new file mode 100644 index 000000000..a93ed1462 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipAESStream.htm @@ -0,0 +1,178 @@ + + + + +ICSharpCode.SharpZipLib.Encryption.ZipAESStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Encryption.ZipAESStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\ZipAESStream.cs
Covered lines:0
Uncovered lines:50
Coverable lines:50
Total lines:134
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)200
Read(...)900
Write(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\ZipAESStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Security.Cryptography;
 4
 5namespace ICSharpCode.SharpZipLib.Encryption
 6{
 7  /// <summary>
 8  /// Encrypts and decrypts AES ZIP
 9  /// </summary>
 10  /// <remarks>
 11  /// Based on information from http://www.winzip.com/aes_info.htm
 12  /// and http://www.gladman.me.uk/cryptography_technology/fileencrypt/
 13  /// </remarks>
 14  internal class ZipAESStream : CryptoStream
 15  {
 16
 17    /// <summary>
 18    /// Constructor
 19    /// </summary>
 20    /// <param name="stream">The stream on which to perform the cryptographic transformation.</param>
 21    /// <param name="transform">Instance of ZipAESTransform</param>
 22    /// <param name="mode">Read or Write</param>
 23    public ZipAESStream(Stream stream, ZipAESTransform transform, CryptoStreamMode mode)
 024      : base(stream, transform, mode)
 25    {
 26
 027      _stream = stream;
 028      _transform = transform;
 029      _slideBuffer = new byte[1024];
 30
 031      _blockAndAuth = CRYPTO_BLOCK_SIZE + AUTH_CODE_LENGTH;
 32
 33      // mode:
 34      //  CryptoStreamMode.Read means we read from "stream" and pass decrypted to our Read() method.
 35      //  Write bypasses this stream and uses the Transform directly.
 036       if (mode != CryptoStreamMode.Read) {
 037        throw new Exception("ZipAESStream only for read");
 38      }
 039    }
 40
 41    // The final n bytes of the AES stream contain the Auth Code.
 42    private const int AUTH_CODE_LENGTH = 10;
 43
 44    private Stream _stream;
 45    private ZipAESTransform _transform;
 46    private byte[] _slideBuffer;
 47    private int _slideBufStartPos;
 48    private int _slideBufFreePos;
 49    // Blocksize is always 16 here, even for AES-256 which has transform.InputBlockSize of 32.
 50    private const int CRYPTO_BLOCK_SIZE = 16;
 51    private int _blockAndAuth;
 52
 53    /// <summary>
 54    /// Reads a sequence of bytes from the current CryptoStream into buffer,
 55    /// and advances the position within the stream by the number of bytes read.
 56    /// </summary>
 57    public override int Read(byte[] buffer, int offset, int count)
 58    {
 059      int nBytes = 0;
 060       while (nBytes < count) {
 61        // Calculate buffer quantities vs read-ahead size, and check for sufficient free space
 062        int byteCount = _slideBufFreePos - _slideBufStartPos;
 63
 64        // Need to handle final block and Auth Code specially, but don't know total data length.
 65        // Maintain a read-ahead equal to the length of (crypto block + Auth Code).
 66        // When that runs out we can detect these final sections.
 067        int lengthToRead = _blockAndAuth - byteCount;
 068         if (_slideBuffer.Length - _slideBufFreePos < lengthToRead) {
 69          // Shift the data to the beginning of the buffer
 070          int iTo = 0;
 071           for (int iFrom = _slideBufStartPos; iFrom < _slideBufFreePos; iFrom++, iTo++) {
 072            _slideBuffer[iTo] = _slideBuffer[iFrom];
 73          }
 074          _slideBufFreePos -= _slideBufStartPos;      // Note the -=
 075          _slideBufStartPos = 0;
 76        }
 077        int obtained = _stream.Read(_slideBuffer, _slideBufFreePos, lengthToRead);
 078        _slideBufFreePos += obtained;
 79
 80        // Recalculate how much data we now have
 081        byteCount = _slideBufFreePos - _slideBufStartPos;
 082         if (byteCount >= _blockAndAuth) {
 83          // At least a 16 byte block and an auth code remains.
 084          _transform.TransformBlock(_slideBuffer,
 085                        _slideBufStartPos,
 086                        CRYPTO_BLOCK_SIZE,
 087                        buffer,
 088                        offset);
 089          nBytes += CRYPTO_BLOCK_SIZE;
 090          offset += CRYPTO_BLOCK_SIZE;
 091          _slideBufStartPos += CRYPTO_BLOCK_SIZE;
 092        } else {
 93          // Last round.
 094           if (byteCount > AUTH_CODE_LENGTH) {
 95            // At least one byte of data plus auth code
 096            int finalBlock = byteCount - AUTH_CODE_LENGTH;
 097            _transform.TransformBlock(_slideBuffer,
 098                          _slideBufStartPos,
 099                          finalBlock,
 0100                          buffer,
 0101                          offset);
 102
 0103            nBytes += finalBlock;
 0104            _slideBufStartPos += finalBlock;
 0105           } else if (byteCount < AUTH_CODE_LENGTH)
 0106            throw new Exception("Internal error missed auth code"); // Coding bug
 107                                        // Final block done. Check Auth code.
 0108          byte[] calcAuthCode = _transform.GetAuthCode();
 0109           for (int i = 0; i < AUTH_CODE_LENGTH; i++) {
 0110             if (calcAuthCode[i] != _slideBuffer[_slideBufStartPos + i]) {
 0111              throw new Exception("AES Authentication Code does not match. This is a super-CRC check on the data in the 
 0112                + "The file may be damaged.");
 113            }
 114          }
 115
 0116          break;  // Reached the auth code
 117        }
 118      }
 0119      return nBytes;
 120    }
 121
 122    /// <summary>
 123    /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the num
 124    /// </summary>
 125    /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream. </para
 126    /// <param name="offset">The byte offset in buffer at which to begin copying bytes to the current stream. </param>
 127    /// <param name="count">The number of bytes to be written to the current stream. </param>
 128    public override void Write(byte[] buffer, int offset, int count)
 129    {
 130      // ZipAESStream is used for reading but not for writing. Writing uses the ZipAESTransform directly.
 0131      throw new NotImplementedException();
 132    }
 133  }
 134}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipAESTransform.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipAESTransform.htm new file mode 100644 index 000000000..d02a5f950 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipAESTransform.htm @@ -0,0 +1,229 @@ + + + + +ICSharpCode.SharpZipLib.Encryption.ZipAESTransform - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Encryption.ZipAESTransform
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\ZipAESTransform.cs
Covered lines:0
Uncovered lines:47
Coverable lines:47
Total lines:183
Line coverage:0%
Branch coverage:0%
+

Metrics

+ + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)400
TransformBlock(...)600
GetAuthCode()200
TransformFinalBlock(...)100
Dispose()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\ZipAESTransform.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3
 4namespace ICSharpCode.SharpZipLib.Encryption
 5{
 6  /// <summary>
 7  /// Transforms stream using AES in CTR mode
 8  /// </summary>
 9  internal class ZipAESTransform : ICryptoTransform
 10  {
 11    private const int PWD_VER_LENGTH = 2;
 12
 13    // WinZip use iteration count of 1000 for PBKDF2 key generation
 14    private const int KEY_ROUNDS = 1000;
 15
 16    // For 128-bit AES (16 bytes) the encryption is implemented as expected.
 17    // For 256-bit AES (32 bytes) WinZip do full 256 bit AES of the nonce to create the encryption
 18    // block but use only the first 16 bytes of it, and discard the second half.
 19    private const int ENCRYPT_BLOCK = 16;
 20
 21    private int _blockSize;
 22    private readonly ICryptoTransform _encryptor;
 23    private readonly byte[] _counterNonce;
 24    private byte[] _encryptBuffer;
 25    private int _encrPos;
 26    private byte[] _pwdVerifier;
 27    private HMACSHA1 _hmacsha1;
 28    private bool _finalised;
 29
 30    private bool _writeMode;
 31
 32    /// <summary>
 33    /// Constructor.
 34    /// </summary>
 35    /// <param name="key">Password string</param>
 36    /// <param name="saltBytes">Random bytes, length depends on encryption strength.
 37    /// 128 bits = 8 bytes, 192 bits = 12 bytes, 256 bits = 16 bytes.</param>
 38    /// <param name="blockSize">The encryption strength, in bytes eg 16 for 128 bits.</param>
 39    /// <param name="writeMode">True when creating a zip, false when reading. For the AuthCode.</param>
 40    ///
 041    public ZipAESTransform(string key, byte[] saltBytes, int blockSize, bool writeMode)
 42    {
 43
 044       if (blockSize != 16 && blockSize != 32) // 24 valid for AES but not supported by Winzip
 045        throw new Exception("Invalid blocksize " + blockSize + ". Must be 16 or 32.");
 046       if (saltBytes.Length != blockSize / 2)
 047        throw new Exception("Invalid salt len. Must be " + blockSize / 2 + " for blocksize " + blockSize);
 48      // initialise the encryption buffer and buffer pos
 049      _blockSize = blockSize;
 050      _encryptBuffer = new byte[_blockSize];
 051      _encrPos = ENCRYPT_BLOCK;
 52
 53      // Performs the equivalent of derive_key in Dr Brian Gladman's pwd2key.c
 054      var pdb = new Rfc2898DeriveBytes(key, saltBytes, KEY_ROUNDS);
 055      var rm = new RijndaelManaged();
 056      rm.Mode = CipherMode.ECB;           // No feedback from cipher for CTR mode
 057      _counterNonce = new byte[_blockSize];
 058      byte[] byteKey1 = pdb.GetBytes(_blockSize);
 059      byte[] byteKey2 = pdb.GetBytes(_blockSize);
 060      _encryptor = rm.CreateEncryptor(byteKey1, byteKey2);
 061      _pwdVerifier = pdb.GetBytes(PWD_VER_LENGTH);
 62      //
 063      _hmacsha1 = new HMACSHA1(byteKey2);
 064      _writeMode = writeMode;
 065    }
 66
 67    /// <summary>
 68    /// Implement the ICryptoTransform method.
 69    /// </summary>
 70    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset
 71    {
 72
 73      // Pass the data stream to the hash algorithm for generating the Auth Code.
 74      // This does not change the inputBuffer. Do this before decryption for read mode.
 075       if (!_writeMode) {
 076        _hmacsha1.TransformBlock(inputBuffer, inputOffset, inputCount, inputBuffer, inputOffset);
 77      }
 78      // Encrypt with AES in CTR mode. Regards to Dr Brian Gladman for this.
 079      int ix = 0;
 080       while (ix < inputCount) {
 081         if (_encrPos == ENCRYPT_BLOCK) {
 82          /* increment encryption nonce   */
 083          int j = 0;
 084           while (++_counterNonce[j] == 0) {
 085            ++j;
 86          }
 87          /* encrypt the nonce to form next xor buffer    */
 088          _encryptor.TransformBlock(_counterNonce, 0, _blockSize, _encryptBuffer, 0);
 089          _encrPos = 0;
 90        }
 091        outputBuffer[ix + outputOffset] = (byte)(inputBuffer[ix + inputOffset] ^ _encryptBuffer[_encrPos++]);
 92        //
 093        ix++;
 94      }
 095       if (_writeMode) {
 96        // This does not change the buffer.
 097        _hmacsha1.TransformBlock(outputBuffer, outputOffset, inputCount, outputBuffer, outputOffset);
 98      }
 099      return inputCount;
 100    }
 101
 102    /// <summary>
 103    /// Returns the 2 byte password verifier
 104    /// </summary>
 105    public byte[] PwdVerifier {
 106      get {
 0107        return _pwdVerifier;
 108      }
 109    }
 110
 111    /// <summary>
 112    /// Returns the 10 byte AUTH CODE to be checked or appended immediately following the AES data stream.
 113    /// </summary>
 114    public byte[] GetAuthCode()
 115    {
 116      // We usually don't get advance notice of final block. Hash requres a TransformFinal.
 0117       if (!_finalised) {
 0118        byte[] dummy = new byte[0];
 0119        _hmacsha1.TransformFinalBlock(dummy, 0, 0);
 0120        _finalised = true;
 121      }
 0122      return _hmacsha1.Hash;
 123    }
 124
 125    #region ICryptoTransform Members
 126
 127    /// <summary>
 128    /// Not implemented.
 129    /// </summary>
 130    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 131    {
 132
 0133      throw new NotImplementedException("ZipAESTransform.TransformFinalBlock");
 134    }
 135
 136    /// <summary>
 137    /// Gets the size of the input data blocks in bytes.
 138    /// </summary>
 139    public int InputBlockSize {
 140      get {
 0141        return _blockSize;
 142      }
 143    }
 144
 145    /// <summary>
 146    /// Gets the size of the output data blocks in bytes.
 147    /// </summary>
 148    public int OutputBlockSize {
 149      get {
 0150        return _blockSize;
 151      }
 152    }
 153
 154    /// <summary>
 155    /// Gets a value indicating whether multiple blocks can be transformed.
 156    /// </summary>
 157    public bool CanTransformMultipleBlocks {
 158      get {
 0159        return true;
 160      }
 161    }
 162
 163    /// <summary>
 164    /// Gets a value indicating whether the current transform can be reused.
 165    /// </summary>
 166    public bool CanReuseTransform {
 167      get {
 0168        return true;
 169      }
 170    }
 171
 172    /// <summary>
 173    /// Cleanup internal state.
 174    /// </summary>
 175    public void Dispose()
 176    {
 0177      _encryptor.Dispose();
 0178    }
 179
 180    #endregion
 181
 182  }
 183}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipConstants.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipConstants.htm new file mode 100644 index 000000000..7992a5341 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipConstants.htm @@ -0,0 +1,640 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipConstants - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipConstants
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipConstants.cs
Covered lines:29
Uncovered lines:8
Coverable lines:37
Total lines:591
Line coverage:78.3%
Branch coverage:63.3%
+

Metrics

+ + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
ConvertToString(...)266.6766.67
ConvertToString(...)266.6766.67
ConvertToStringExt(...)38080
ConvertToStringExt(...)38080
ConvertToArray(...)2100100
ConvertToArray(...)38080
.ctor()100
.cctor()5100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipConstants.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Text;
 3using System.Threading;
 4
 5namespace ICSharpCode.SharpZipLib.Zip
 6{
 7  #region Enumerations
 8
 9  /// <summary>
 10  /// Determines how entries are tested to see if they should use Zip64 extensions or not.
 11  /// </summary>
 12  public enum UseZip64
 13  {
 14    /// <summary>
 15    /// Zip64 will not be forced on entries during processing.
 16    /// </summary>
 17    /// <remarks>An entry can have this overridden if required <see cref="ZipEntry.ForceZip64"></see></remarks>
 18    Off,
 19    /// <summary>
 20    /// Zip64 should always be used.
 21    /// </summary>
 22    On,
 23    /// <summary>
 24    /// #ZipLib will determine use based on entry values when added to archive.
 25    /// </summary>
 26    Dynamic,
 27  }
 28
 29  /// <summary>
 30  /// The kind of compression used for an entry in an archive
 31  /// </summary>
 32  public enum CompressionMethod
 33  {
 34    /// <summary>
 35    /// A direct copy of the file contents is held in the archive
 36    /// </summary>
 37    Stored = 0,
 38
 39    /// <summary>
 40    /// Common Zip compression method using a sliding dictionary
 41    /// of up to 32KB and secondary compression from Huffman/Shannon-Fano trees
 42    /// </summary>
 43    Deflated = 8,
 44
 45    /// <summary>
 46    /// An extension to deflate with a 64KB window. Not supported by #Zip currently
 47    /// </summary>
 48    Deflate64 = 9,
 49
 50    /// <summary>
 51    /// BZip2 compression. Not supported by #Zip.
 52    /// </summary>
 53    BZip2 = 11,
 54
 55    /// <summary>
 56    /// WinZip special for AES encryption, Now supported by #Zip.
 57    /// </summary>
 58    WinZipAES = 99,
 59
 60  }
 61
 62  /// <summary>
 63  /// Identifies the encryption algorithm used for an entry
 64  /// </summary>
 65  public enum EncryptionAlgorithm
 66  {
 67    /// <summary>
 68    /// No encryption has been used.
 69    /// </summary>
 70    None = 0,
 71    /// <summary>
 72    /// Encrypted using PKZIP 2.0 or 'classic' encryption.
 73    /// </summary>
 74    PkzipClassic = 1,
 75    /// <summary>
 76    /// DES encryption has been used.
 77    /// </summary>
 78    Des = 0x6601,
 79    /// <summary>
 80    /// RC2 encryption has been used for encryption.
 81    /// </summary>
 82    RC2 = 0x6602,
 83    /// <summary>
 84    /// Triple DES encryption with 168 bit keys has been used for this entry.
 85    /// </summary>
 86    TripleDes168 = 0x6603,
 87    /// <summary>
 88    /// Triple DES with 112 bit keys has been used for this entry.
 89    /// </summary>
 90    TripleDes112 = 0x6609,
 91    /// <summary>
 92    /// AES 128 has been used for encryption.
 93    /// </summary>
 94    Aes128 = 0x660e,
 95    /// <summary>
 96    /// AES 192 has been used for encryption.
 97    /// </summary>
 98    Aes192 = 0x660f,
 99    /// <summary>
 100    /// AES 256 has been used for encryption.
 101    /// </summary>
 102    Aes256 = 0x6610,
 103    /// <summary>
 104    /// RC2 corrected has been used for encryption.
 105    /// </summary>
 106    RC2Corrected = 0x6702,
 107    /// <summary>
 108    /// Blowfish has been used for encryption.
 109    /// </summary>
 110    Blowfish = 0x6720,
 111    /// <summary>
 112    /// Twofish has been used for encryption.
 113    /// </summary>
 114    Twofish = 0x6721,
 115    /// <summary>
 116    /// RC4 has been used for encryption.
 117    /// </summary>
 118    RC4 = 0x6801,
 119    /// <summary>
 120    /// An unknown algorithm has been used for encryption.
 121    /// </summary>
 122    Unknown = 0xffff
 123  }
 124
 125  /// <summary>
 126  /// Defines the contents of the general bit flags field for an archive entry.
 127  /// </summary>
 128  [Flags]
 129  public enum GeneralBitFlags
 130  {
 131    /// <summary>
 132    /// Bit 0 if set indicates that the file is encrypted
 133    /// </summary>
 134    Encrypted = 0x0001,
 135    /// <summary>
 136    /// Bits 1 and 2 - Two bits defining the compression method (only for Method 6 Imploding and 8,9 Deflating)
 137    /// </summary>
 138    Method = 0x0006,
 139    /// <summary>
 140    /// Bit 3 if set indicates a trailing data desciptor is appended to the entry data
 141    /// </summary>
 142    Descriptor = 0x0008,
 143    /// <summary>
 144    /// Bit 4 is reserved for use with method 8 for enhanced deflation
 145    /// </summary>
 146    ReservedPKware4 = 0x0010,
 147    /// <summary>
 148    /// Bit 5 if set indicates the file contains Pkzip compressed patched data.
 149    /// Requires version 2.7 or greater.
 150    /// </summary>
 151    Patched = 0x0020,
 152    /// <summary>
 153    /// Bit 6 if set indicates strong encryption has been used for this entry.
 154    /// </summary>
 155    StrongEncryption = 0x0040,
 156    /// <summary>
 157    /// Bit 7 is currently unused
 158    /// </summary>
 159    Unused7 = 0x0080,
 160    /// <summary>
 161    /// Bit 8 is currently unused
 162    /// </summary>
 163    Unused8 = 0x0100,
 164    /// <summary>
 165    /// Bit 9 is currently unused
 166    /// </summary>
 167    Unused9 = 0x0200,
 168    /// <summary>
 169    /// Bit 10 is currently unused
 170    /// </summary>
 171    Unused10 = 0x0400,
 172    /// <summary>
 173    /// Bit 11 if set indicates the filename and
 174    /// comment fields for this file must be encoded using UTF-8.
 175    /// </summary>
 176    UnicodeText = 0x0800,
 177    /// <summary>
 178    /// Bit 12 is documented as being reserved by PKware for enhanced compression.
 179    /// </summary>
 180    EnhancedCompress = 0x1000,
 181    /// <summary>
 182    /// Bit 13 if set indicates that values in the local header are masked to hide
 183    /// their actual values, and the central directory is encrypted.
 184    /// </summary>
 185    /// <remarks>
 186    /// Used when encrypting the central directory contents.
 187    /// </remarks>
 188    HeaderMasked = 0x2000,
 189    /// <summary>
 190    /// Bit 14 is documented as being reserved for use by PKware
 191    /// </summary>
 192    ReservedPkware14 = 0x4000,
 193    /// <summary>
 194    /// Bit 15 is documented as being reserved for use by PKware
 195    /// </summary>
 196    ReservedPkware15 = 0x8000
 197  }
 198
 199  #endregion
 200
 201  /// <summary>
 202  /// This class contains constants used for Zip format files
 203  /// </summary>
 204  public sealed class ZipConstants
 205  {
 206    #region Versions
 207    /// <summary>
 208    /// The version made by field for entries in the central header when created by this library
 209    /// </summary>
 210    /// <remarks>
 211    /// This is also the Zip version for the library when comparing against the version required to extract
 212    /// for an entry.  See <see cref="ZipEntry.CanDecompress"/>.
 213    /// </remarks>
 214    public const int VersionMadeBy = 51; // was 45 before AES
 215
 216    /// <summary>
 217    /// The version made by field for entries in the central header when created by this library
 218    /// </summary>
 219    /// <remarks>
 220    /// This is also the Zip version for the library when comparing against the version required to extract
 221    /// for an entry.  See <see cref="ZipInputStream.CanDecompressEntry">ZipInputStream.CanDecompressEntry</see>.
 222    /// </remarks>
 223    [Obsolete("Use VersionMadeBy instead")]
 224    public const int VERSION_MADE_BY = 51;
 225
 226    /// <summary>
 227    /// The minimum version required to support strong encryption
 228    /// </summary>
 229    public const int VersionStrongEncryption = 50;
 230
 231    /// <summary>
 232    /// The minimum version required to support strong encryption
 233    /// </summary>
 234    [Obsolete("Use VersionStrongEncryption instead")]
 235    public const int VERSION_STRONG_ENCRYPTION = 50;
 236
 237    /// <summary>
 238    /// Version indicating AES encryption
 239    /// </summary>
 240    public const int VERSION_AES = 51;
 241
 242    /// <summary>
 243    /// The version required for Zip64 extensions (4.5 or higher)
 244    /// </summary>
 245    public const int VersionZip64 = 45;
 246    #endregion
 247
 248    #region Header Sizes
 249    /// <summary>
 250    /// Size of local entry header (excluding variable length fields at end)
 251    /// </summary>
 252    public const int LocalHeaderBaseSize = 30;
 253
 254    /// <summary>
 255    /// Size of local entry header (excluding variable length fields at end)
 256    /// </summary>
 257    [Obsolete("Use LocalHeaderBaseSize instead")]
 258    public const int LOCHDR = 30;
 259
 260    /// <summary>
 261    /// Size of Zip64 data descriptor
 262    /// </summary>
 263    public const int Zip64DataDescriptorSize = 24;
 264
 265    /// <summary>
 266    /// Size of data descriptor
 267    /// </summary>
 268    public const int DataDescriptorSize = 16;
 269
 270    /// <summary>
 271    /// Size of data descriptor
 272    /// </summary>
 273    [Obsolete("Use DataDescriptorSize instead")]
 274    public const int EXTHDR = 16;
 275
 276    /// <summary>
 277    /// Size of central header entry (excluding variable fields)
 278    /// </summary>
 279    public const int CentralHeaderBaseSize = 46;
 280
 281    /// <summary>
 282    /// Size of central header entry
 283    /// </summary>
 284    [Obsolete("Use CentralHeaderBaseSize instead")]
 285    public const int CENHDR = 46;
 286
 287    /// <summary>
 288    /// Size of end of central record (excluding variable fields)
 289    /// </summary>
 290    public const int EndOfCentralRecordBaseSize = 22;
 291
 292    /// <summary>
 293    /// Size of end of central record (excluding variable fields)
 294    /// </summary>
 295    [Obsolete("Use EndOfCentralRecordBaseSize instead")]
 296    public const int ENDHDR = 22;
 297
 298    /// <summary>
 299    /// Size of 'classic' cryptographic header stored before any entry data
 300    /// </summary>
 301    public const int CryptoHeaderSize = 12;
 302
 303    /// <summary>
 304    /// Size of cryptographic header stored before entry data
 305    /// </summary>
 306    [Obsolete("Use CryptoHeaderSize instead")]
 307    public const int CRYPTO_HEADER_SIZE = 12;
 308    #endregion
 309
 310    #region Header Signatures
 311
 312    /// <summary>
 313    /// Signature for local entry header
 314    /// </summary>
 315    public const int LocalHeaderSignature = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
 316
 317    /// <summary>
 318    /// Signature for local entry header
 319    /// </summary>
 320    [Obsolete("Use LocalHeaderSignature instead")]
 321    public const int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
 322
 323    /// <summary>
 324    /// Signature for spanning entry
 325    /// </summary>
 326    public const int SpanningSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
 327
 328    /// <summary>
 329    /// Signature for spanning entry
 330    /// </summary>
 331    [Obsolete("Use SpanningSignature instead")]
 332    public const int SPANNINGSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
 333
 334    /// <summary>
 335    /// Signature for temporary spanning entry
 336    /// </summary>
 337    public const int SpanningTempSignature = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);
 338
 339    /// <summary>
 340    /// Signature for temporary spanning entry
 341    /// </summary>
 342    [Obsolete("Use SpanningTempSignature instead")]
 343    public const int SPANTEMPSIG = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);
 344
 345    /// <summary>
 346    /// Signature for data descriptor
 347    /// </summary>
 348    /// <remarks>
 349    /// This is only used where the length, Crc, or compressed size isnt known when the
 350    /// entry is created and the output stream doesnt support seeking.
 351    /// The local entry cannot be 'patched' with the correct values in this case
 352    /// so the values are recorded after the data prefixed by this header, as well as in the central directory.
 353    /// </remarks>
 354    public const int DataDescriptorSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
 355
 356    /// <summary>
 357    /// Signature for data descriptor
 358    /// </summary>
 359    /// <remarks>
 360    /// This is only used where the length, Crc, or compressed size isnt known when the
 361    /// entry is created and the output stream doesnt support seeking.
 362    /// The local entry cannot be 'patched' with the correct values in this case
 363    /// so the values are recorded after the data prefixed by this header, as well as in the central directory.
 364    /// </remarks>
 365    [Obsolete("Use DataDescriptorSignature instead")]
 366    public const int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
 367
 368    /// <summary>
 369    /// Signature for central header
 370    /// </summary>
 371    [Obsolete("Use CentralHeaderSignature instead")]
 372    public const int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
 373
 374    /// <summary>
 375    /// Signature for central header
 376    /// </summary>
 377    public const int CentralHeaderSignature = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
 378
 379    /// <summary>
 380    /// Signature for Zip64 central file header
 381    /// </summary>
 382    public const int Zip64CentralFileHeaderSignature = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);
 383
 384    /// <summary>
 385    /// Signature for Zip64 central file header
 386    /// </summary>
 387    [Obsolete("Use Zip64CentralFileHeaderSignature instead")]
 388    public const int CENSIG64 = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);
 389
 390    /// <summary>
 391    /// Signature for Zip64 central directory locator
 392    /// </summary>
 393    public const int Zip64CentralDirLocatorSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);
 394
 395    /// <summary>
 396    /// Signature for archive extra data signature (were headers are encrypted).
 397    /// </summary>
 398    public const int ArchiveExtraDataSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);
 399
 400    /// <summary>
 401    /// Central header digitial signature
 402    /// </summary>
 403    public const int CentralHeaderDigitalSignature = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
 404
 405    /// <summary>
 406    /// Central header digitial signature
 407    /// </summary>
 408    [Obsolete("Use CentralHeaderDigitalSignaure instead")]
 409    public const int CENDIGITALSIG = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
 410
 411    /// <summary>
 412    /// End of central directory record signature
 413    /// </summary>
 414    public const int EndOfCentralDirectorySignature = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
 415
 416    /// <summary>
 417    /// End of central directory record signature
 418    /// </summary>
 419    [Obsolete("Use EndOfCentralDirectorySignature instead")]
 420    public const int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
 421    #endregion
 422
 423    /// <remarks>
 424    /// Get OEM codepage from NetFX, which parses the NLP file with culture info table etc etc.
 425    /// But sometimes it yields the special value of 1 which is nicknamed <c>CodePageNoOEM</c> in <see cref="Encoding"/>
 426    /// This was observed on Ukranian and Hindu systems.
 427    /// Given this value, <see cref="Encoding.GetEncoding(int)"/> throws an <see cref="ArgumentException"/>.
 428    /// So replace it with some fallback, e.g. 437 which is the default cpcp in a console in a default Windows installat
 429    /// </remarks>
 1430    static int defaultCodePage =
 1431      // these values cause ArgumentException in subsequent calls to Encoding::GetEncoding()
 1432      ((Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 1) || (Thread.CurrentThread.CurrentCulture.TextInfo.
 1433      ? 437 // The default OEM encoding in a console in a default Windows installation, as a fallback.
 1434      : Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage;
 435
 436    /// <summary>
 437    /// Default encoding used for string conversion.  0 gives the default system OEM code page.
 438    /// Dont use unicode encodings if you want to be Zip compatible!
 439    /// Using the default code page isnt the full solution neccessarily
 440    /// there are many variable factors, codepage 850 is often a good choice for
 441    /// European users, however be careful about compatability.
 442    /// </summary>
 443    public static int DefaultCodePage {
 444      get {
 263830445        return defaultCodePage;
 446      }
 447      set {
 1448         if ((value < 0) || (value > 65535) ||
 1449          (value == 1) || (value == 2) || (value == 3) || (value == 42)) {
 0450          throw new ArgumentOutOfRangeException(nameof(value));
 451        }
 452
 1453        defaultCodePage = value;
 1454      }
 455    }
 456
 457    /// <summary>
 458    /// Convert a portion of a byte array to a string.
 459    /// </summary>
 460    /// <param name="data">
 461    /// Data to convert to string
 462    /// </param>
 463    /// <param name="count">
 464    /// Number of bytes to convert starting from index 0
 465    /// </param>
 466    /// <returns>
 467    /// data[0]..data[count - 1] converted to a string
 468    /// </returns>
 469    public static string ConvertToString(byte[] data, int count)
 470    {
 131956471       if (data == null) {
 0472        return string.Empty;
 473      }
 474
 131956475      return Encoding.GetEncoding(DefaultCodePage).GetString(data, 0, count);
 476    }
 477
 478    /// <summary>
 479    /// Convert a byte array to string
 480    /// </summary>
 481    /// <param name="data">
 482    /// Byte array to convert
 483    /// </param>
 484    /// <returns>
 485    /// <paramref name="data">data</paramref>converted to a string
 486    /// </returns>
 487    public static string ConvertToString(byte[] data)
 488    {
 12489       if (data == null) {
 0490        return string.Empty;
 491      }
 12492      return ConvertToString(data, data.Length);
 493    }
 494
 495    /// <summary>
 496    /// Convert a byte array to string
 497    /// </summary>
 498    /// <param name="flags">The applicable general purpose bits flags</param>
 499    /// <param name="data">
 500    /// Byte array to convert
 501    /// </param>
 502    /// <param name="count">The number of bytes to convert.</param>
 503    /// <returns>
 504    /// <paramref name="data">data</paramref>converted to a string
 505    /// </returns>
 506    public static string ConvertToStringExt(int flags, byte[] data, int count)
 507    {
 65956508       if (data == null) {
 0509        return string.Empty;
 510      }
 511
 65956512       if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) {
 5513        return Encoding.UTF8.GetString(data, 0, count);
 514      } else {
 65951515        return ConvertToString(data, count);
 516      }
 517    }
 518
 519    /// <summary>
 520    /// Convert a byte array to string
 521    /// </summary>
 522    /// <param name="data">
 523    /// Byte array to convert
 524    /// </param>
 525    /// <param name="flags">The applicable general purpose bits flags</param>
 526    /// <returns>
 527    /// <paramref name="data">data</paramref>converted to a string
 528    /// </returns>
 529    public static string ConvertToStringExt(int flags, byte[] data)
 530    {
 66000531       if (data == null) {
 0532        return string.Empty;
 533      }
 534
 66000535       if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) {
 7536        return Encoding.UTF8.GetString(data, 0, data.Length);
 537      } else {
 65993538        return ConvertToString(data, data.Length);
 539      }
 540    }
 541
 542    /// <summary>
 543    /// Convert a string to a byte array
 544    /// </summary>
 545    /// <param name="str">
 546    /// String to convert to an array
 547    /// </param>
 548    /// <returns>Converted array</returns>
 549    public static byte[] ConvertToArray(string str)
 550    {
 131891551       if (str == null) {
 17552        return new byte[0];
 553      }
 554
 131874555      return Encoding.GetEncoding(DefaultCodePage).GetBytes(str);
 556    }
 557
 558    /// <summary>
 559    /// Convert a string to a byte array
 560    /// </summary>
 561    /// <param name="flags">The applicable <see cref="GeneralBitFlags">general purpose bits flags</see></param>
 562    /// <param name="str">
 563    /// String to convert to an array
 564    /// </param>
 565    /// <returns>Converted array</returns>
 566    public static byte[] ConvertToArray(int flags, string str)
 567    {
 131777568       if (str == null) {
 0569        return new byte[0];
 570      }
 571
 131777572       if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) {
 12573        return Encoding.UTF8.GetBytes(str);
 574      } else {
 131765575        return ConvertToArray(str);
 576      }
 577    }
 578
 579
 580    /// <summary>
 581    /// Initialise default instance of <see cref="ZipConstants">ZipConstants</see>
 582    /// </summary>
 583    /// <remarks>
 584    /// Private to prevent instances being created.
 585    /// </remarks>
 0586    ZipConstants()
 587    {
 588      // Do nothing
 0589    }
 590  }
 591}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipEntry.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipEntry.htm new file mode 100644 index 000000000..8e988a284 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipEntry.htm @@ -0,0 +1,1231 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipEntry - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipEntry
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipEntry.cs
Covered lines:219
Uncovered lines:69
Coverable lines:288
Total lines:1175
Line coverage:76%
Branch coverage:59.5%
+

Metrics

+ + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)1100100
.ctor(...)587.577.78
.ctor(...)396.1560
HasDosAttributes(...)4100100
ForceZip64()1100100
IsZip64Forced()1100100
ProcessExtraData(...)1172.2266.67
GetDateTime(...)59033.33
ProcessAESExtraData(...)300
IsCompressionMethodSupported()1100100
Clone()2100100
ToString()100
IsCompressionMethodSupported(...)2100100
CleanName(...)562.555.56
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipEntry.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Zip
 5{
 6  /// <summary>
 7  /// Defines known values for the <see cref="HostSystemID"/> property.
 8  /// </summary>
 9  public enum HostSystemID
 10  {
 11    /// <summary>
 12    /// Host system = MSDOS
 13    /// </summary>
 14    Msdos = 0,
 15    /// <summary>
 16    /// Host system = Amiga
 17    /// </summary>
 18    Amiga = 1,
 19    /// <summary>
 20    /// Host system = Open VMS
 21    /// </summary>
 22    OpenVms = 2,
 23    /// <summary>
 24    /// Host system = Unix
 25    /// </summary>
 26    Unix = 3,
 27    /// <summary>
 28    /// Host system = VMCms
 29    /// </summary>
 30    VMCms = 4,
 31    /// <summary>
 32    /// Host system = Atari ST
 33    /// </summary>
 34    AtariST = 5,
 35    /// <summary>
 36    /// Host system = OS2
 37    /// </summary>
 38    OS2 = 6,
 39    /// <summary>
 40    /// Host system = Macintosh
 41    /// </summary>
 42    Macintosh = 7,
 43    /// <summary>
 44    /// Host system = ZSystem
 45    /// </summary>
 46    ZSystem = 8,
 47    /// <summary>
 48    /// Host system = Cpm
 49    /// </summary>
 50    Cpm = 9,
 51    /// <summary>
 52    /// Host system = Windows NT
 53    /// </summary>
 54    WindowsNT = 10,
 55    /// <summary>
 56    /// Host system = MVS
 57    /// </summary>
 58    MVS = 11,
 59    /// <summary>
 60    /// Host system = VSE
 61    /// </summary>
 62    Vse = 12,
 63    /// <summary>
 64    /// Host system = Acorn RISC
 65    /// </summary>
 66    AcornRisc = 13,
 67    /// <summary>
 68    /// Host system = VFAT
 69    /// </summary>
 70    Vfat = 14,
 71    /// <summary>
 72    /// Host system = Alternate MVS
 73    /// </summary>
 74    AlternateMvs = 15,
 75    /// <summary>
 76    /// Host system = BEOS
 77    /// </summary>
 78    BeOS = 16,
 79    /// <summary>
 80    /// Host system = Tandem
 81    /// </summary>
 82    Tandem = 17,
 83    /// <summary>
 84    /// Host system = OS400
 85    /// </summary>
 86    OS400 = 18,
 87    /// <summary>
 88    /// Host system = OSX
 89    /// </summary>
 90    OSX = 19,
 91    /// <summary>
 92    /// Host system = WinZIP AES
 93    /// </summary>
 94    WinZipAES = 99,
 95  }
 96
 97  /// <summary>
 98  /// This class represents an entry in a zip archive.  This can be a file
 99  /// or a directory
 100  /// ZipFile and ZipInputStream will give you instances of this class as
 101  /// information about the members in an archive.  ZipOutputStream
 102  /// uses an instance of this class when creating an entry in a Zip file.
 103  /// <br/>
 104  /// <br/>Author of the original java version : Jochen Hoenicke
 105  /// </summary>
 106  public class ZipEntry : ICloneable
 107  {
 108    [Flags]
 109    enum Known : byte
 110    {
 111      None = 0,
 112      Size = 0x01,
 113      CompressedSize = 0x02,
 114      Crc = 0x04,
 115      Time = 0x08,
 116      ExternalAttributes = 0x10,
 117    }
 118
 119    #region Constructors
 120    /// <summary>
 121    /// Creates a zip entry with the given name.
 122    /// </summary>
 123    /// <param name="name">
 124    /// The name for this entry. Can include directory components.
 125    /// The convention for names is 'unix' style paths with relative names only.
 126    /// There are with no device names and path elements are separated by '/' characters.
 127    /// </param>
 128    /// <exception cref="ArgumentNullException">
 129    /// The name passed is null
 130    /// </exception>
 131    public ZipEntry(string name)
 65841132      : this(name, 0, ZipConstants.VersionMadeBy, CompressionMethod.Deflated)
 133    {
 65840134    }
 135
 136    /// <summary>
 137    /// Creates a zip entry with the given name and version required to extract
 138    /// </summary>
 139    /// <param name="name">
 140    /// The name for this entry. Can include directory components.
 141    /// The convention for names is 'unix'  style paths with no device names and
 142    /// path elements separated by '/' characters.  This is not enforced see <see cref="CleanName(string)">CleanName</se
 143    /// on how to ensure names are valid if this is desired.
 144    /// </param>
 145    /// <param name="versionRequiredToExtract">
 146    /// The minimum 'feature version' required this entry
 147    /// </param>
 148    /// <exception cref="ArgumentNullException">
 149    /// The name passed is null
 150    /// </exception>
 151    internal ZipEntry(string name, int versionRequiredToExtract)
 81152      : this(name, versionRequiredToExtract, ZipConstants.VersionMadeBy,
 81153      CompressionMethod.Deflated)
 154    {
 81155    }
 156
 157    /// <summary>
 158    /// Initializes an entry with the given name and made by information
 159    /// </summary>
 160    /// <param name="name">Name for this entry</param>
 161    /// <param name="madeByInfo">Version and HostSystem Information</param>
 162    /// <param name="versionRequiredToExtract">Minimum required zip feature version required to extract this entry</para
 163    /// <param name="method">Compression method for this entry.</param>
 164    /// <exception cref="ArgumentNullException">
 165    /// The name passed is null
 166    /// </exception>
 167    /// <exception cref="ArgumentOutOfRangeException">
 168    /// versionRequiredToExtract should be 0 (auto-calculate) or > 10
 169    /// </exception>
 170    /// <remarks>
 171    /// This constructor is used by the ZipFile class when reading from the central header
 172    /// It is not generally useful, use the constructor specifying the name only.
 173    /// </remarks>
 131878174    internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo,
 131878175      CompressionMethod method)
 176    {
 131878177       if (name == null) {
 1178        throw new ArgumentNullException(nameof(name));
 179      }
 180
 131877181       if (name.Length > 0xffff) {
 0182        throw new ArgumentException("Name is too long", nameof(name));
 183      }
 184
 131877185       if ((versionRequiredToExtract != 0) && (versionRequiredToExtract < 10)) {
 0186        throw new ArgumentOutOfRangeException(nameof(versionRequiredToExtract));
 187      }
 188
 131877189      this.DateTime = DateTime.Now;
 131877190      this.name = CleanName(name);
 131877191      this.versionMadeBy = (ushort)madeByInfo;
 131877192      this.versionToExtract = (ushort)versionRequiredToExtract;
 131877193      this.method = method;
 131877194    }
 195
 196    /// <summary>
 197    /// Creates a deep copy of the given zip entry.
 198    /// </summary>
 199    /// <param name="entry">
 200    /// The entry to copy.
 201    /// </param>
 202    [Obsolete("Use Clone instead")]
 1203    public ZipEntry(ZipEntry entry)
 204    {
 1205       if (entry == null) {
 0206        throw new ArgumentNullException(nameof(entry));
 207      }
 208
 1209      known = entry.known;
 1210      name = entry.name;
 1211      size = entry.size;
 1212      compressedSize = entry.compressedSize;
 1213      crc = entry.crc;
 1214      dosTime = entry.dosTime;
 1215      dateTime = entry.dateTime;
 1216      method = entry.method;
 1217      comment = entry.comment;
 1218      versionToExtract = entry.versionToExtract;
 1219      versionMadeBy = entry.versionMadeBy;
 1220      externalFileAttributes = entry.externalFileAttributes;
 1221      flags = entry.flags;
 222
 1223      zipFileIndex = entry.zipFileIndex;
 1224      offset = entry.offset;
 225
 1226      forceZip64_ = entry.forceZip64_;
 227
 1228       if (entry.extra != null) {
 1229        extra = new byte[entry.extra.Length];
 1230        Array.Copy(entry.extra, 0, extra, 0, entry.extra.Length);
 231      }
 1232    }
 233
 234    #endregion
 235
 236    /// <summary>
 237    /// Get a value indicating wether the entry has a CRC value available.
 238    /// </summary>
 239    public bool HasCrc {
 240      get {
 65754241        return (known & Known.Crc) != 0;
 242      }
 243    }
 244
 245    /// <summary>
 246    /// Get/Set flag indicating if entry is encrypted.
 247    /// A simple helper routine to aid interpretation of <see cref="Flags">flags</see>
 248    /// </summary>
 249    /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>
 250    public bool IsCrypted {
 251      get {
 592001252        return (flags & 1) != 0;
 253      }
 254      set {
 65738255         if (value) {
 38256          flags |= 1;
 38257        } else {
 65700258          flags &= ~1;
 259        }
 65700260      }
 261    }
 262
 263    /// <summary>
 264    /// Get / set a flag indicating wether entry name and comment text are
 265    /// encoded in <a href="http://www.unicode.org">unicode UTF8</a>.
 266    /// </summary>
 267    /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>
 268    public bool IsUnicodeText {
 269      get {
 4270        return (flags & (int)GeneralBitFlags.UnicodeText) != 0;
 271      }
 272      set {
 177273         if (value) {
 8274          flags |= (int)GeneralBitFlags.UnicodeText;
 8275        } else {
 169276          flags &= ~(int)GeneralBitFlags.UnicodeText;
 277        }
 169278      }
 279    }
 280
 281    /// <summary>
 282    /// Value used during password checking for PKZIP 2.0 / 'classic' encryption.
 283    /// </summary>
 284    internal byte CryptoCheckValue {
 285      get {
 34286        return cryptoCheckValue_;
 287      }
 288
 289      set {
 66037290        cryptoCheckValue_ = value;
 66037291      }
 292    }
 293
 294    /// <summary>
 295    /// Get/Set general purpose bit flag for entry
 296    /// </summary>
 297    /// <remarks>
 298    /// General purpose bit flag<br/>
 299    /// <br/>
 300    /// Bit 0: If set, indicates the file is encrypted<br/>
 301    /// Bit 1-2 Only used for compression type 6 Imploding, and 8, 9 deflating<br/>
 302    /// Imploding:<br/>
 303    /// Bit 1 if set indicates an 8K sliding dictionary was used.  If clear a 4k dictionary was used<br/>
 304    /// Bit 2 if set indicates 3 Shannon-Fanno trees were used to encode the sliding dictionary, 2 otherwise<br/>
 305    /// <br/>
 306    /// Deflating:<br/>
 307    ///   Bit 2    Bit 1<br/>
 308    ///     0        0       Normal compression was used<br/>
 309    ///     0        1       Maximum compression was used<br/>
 310    ///     1        0       Fast compression was used<br/>
 311    ///     1        1       Super fast compression was used<br/>
 312    /// <br/>
 313    /// Bit 3: If set, the fields crc-32, compressed size
 314    /// and uncompressed size are were not able to be written during zip file creation
 315    /// The correct values are held in a data descriptor immediately following the compressed data. <br/>
 316    /// Bit 4: Reserved for use by PKZIP for enhanced deflating<br/>
 317    /// Bit 5: If set indicates the file contains compressed patch data<br/>
 318    /// Bit 6: If set indicates strong encryption was used.<br/>
 319    /// Bit 7-10: Unused or reserved<br/>
 320    /// Bit 11: If set the name and comments for this entry are in <a href="http://www.unicode.org">unicode</a>.<br/>
 321    /// Bit 12-15: Unused or reserved<br/>
 322    /// </remarks>
 323    /// <seealso cref="IsUnicodeText"></seealso>
 324    /// <seealso cref="IsCrypted"></seealso>
 325    public int Flags {
 326      get {
 395994327        return flags;
 328      }
 329      set {
 66249330        flags = value;
 66249331      }
 332    }
 333
 334    /// <summary>
 335    /// Get/Set index of this entry in Zip file
 336    /// </summary>
 337    /// <remarks>This is only valid when the entry is part of a <see cref="ZipFile"></see></remarks>
 338    public long ZipFileIndex {
 339      get {
 65933340        return zipFileIndex;
 341      }
 342      set {
 65956343        zipFileIndex = value;
 65956344      }
 345    }
 346
 347    /// <summary>
 348    /// Get/set offset for use in central header
 349    /// </summary>
 350    public long Offset {
 351      get {
 396693352        return offset;
 353      }
 354      set {
 131833355        offset = value;
 131833356      }
 357    }
 358
 359    /// <summary>
 360    /// Get/Set external file attributes as an integer.
 361    /// The values of this are operating system dependant see
 362    /// <see cref="HostSystem">HostSystem</see> for details
 363    /// </summary>
 364    public int ExternalFileAttributes {
 365      get {
 527438366         if ((known & Known.ExternalAttributes) == 0) {
 65824367          return -1;
 368        } else {
 461614369          return externalFileAttributes;
 370        }
 371      }
 372
 373      set {
 65965374        externalFileAttributes = value;
 65965375        known |= Known.ExternalAttributes;
 65965376      }
 377    }
 378
 379    /// <summary>
 380    /// Get the version made by for this entry or zero if unknown.
 381    /// The value / 10 indicates the major version number, and
 382    /// the value mod 10 is the minor version number
 383    /// </summary>
 384    public int VersionMadeBy {
 385      get {
 0386        return (versionMadeBy & 0xff);
 387      }
 388    }
 389
 390    /// <summary>
 391    /// Get a value indicating this entry is for a DOS/Windows system.
 392    /// </summary>
 393    public bool IsDOSEntry {
 394      get {
 2395        return ((HostSystem == (int)HostSystemID.Msdos) ||
 2396          (HostSystem == (int)HostSystemID.WindowsNT));
 397      }
 398    }
 399
 400    /// <summary>
 401    /// Test the external attributes for this <see cref="ZipEntry"/> to
 402    /// see if the external attributes are Dos based (including WINNT and variants)
 403    /// and match the values
 404    /// </summary>
 405    /// <param name="attributes">The attributes to test.</param>
 406    /// <returns>Returns true if the external attributes are known to be DOS/Windows
 407    /// based and have the same attributes set as the value passed.</returns>
 408    bool HasDosAttributes(int attributes)
 409    {
 920886410      bool result = false;
 920886411       if ((known & Known.ExternalAttributes) != 0) {
 461462412        result |= (((HostSystem == (int)HostSystemID.Msdos) ||
 461462413          (HostSystem == (int)HostSystemID.WindowsNT)) &&
 461462414          (ExternalFileAttributes & attributes) == attributes);
 415      }
 920886416      return result;
 417    }
 418
 419    /// <summary>
 420    /// Gets the compatability information for the <see cref="ExternalFileAttributes">external file attribute</see>
 421    /// If the external file attributes are compatible with MS-DOS and can be read
 422    /// by PKZIP for DOS version 2.04g then this value will be zero.  Otherwise the value
 423    /// will be non-zero and identify the host system on which the attributes are compatible.
 424    /// </summary>
 425    ///
 426    /// <remarks>
 427    /// The values for this as defined in the Zip File format and by others are shown below.  The values are somewhat
 428    /// misleading in some cases as they are not all used as shown.  You should consult the relevant documentation
 429    /// to obtain up to date and correct information.  The modified appnote by the infozip group is
 430    /// particularly helpful as it documents a lot of peculiarities.  The document is however a little dated.
 431    /// <list type="table">
 432    /// <item>0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)</item>
 433    /// <item>1 - Amiga</item>
 434    /// <item>2 - OpenVMS</item>
 435    /// <item>3 - Unix</item>
 436    /// <item>4 - VM/CMS</item>
 437    /// <item>5 - Atari ST</item>
 438    /// <item>6 - OS/2 HPFS</item>
 439    /// <item>7 - Macintosh</item>
 440    /// <item>8 - Z-System</item>
 441    /// <item>9 - CP/M</item>
 442    /// <item>10 - Windows NTFS</item>
 443    /// <item>11 - MVS (OS/390 - Z/OS)</item>
 444    /// <item>12 - VSE</item>
 445    /// <item>13 - Acorn Risc</item>
 446    /// <item>14 - VFAT</item>
 447    /// <item>15 - Alternate MVS</item>
 448    /// <item>16 - BeOS</item>
 449    /// <item>17 - Tandem</item>
 450    /// <item>18 - OS/400</item>
 451    /// <item>19 - OS/X (Darwin)</item>
 452    /// <item>99 - WinZip AES</item>
 453    /// <item>remainder - unused</item>
 454    /// </list>
 455    /// </remarks>
 456    public int HostSystem {
 457      get {
 461464458        return (versionMadeBy >> 8) & 0xff;
 459      }
 460
 461      set {
 0462        versionMadeBy &= 0xff;
 0463        versionMadeBy |= (ushort)((value & 0xff) << 8);
 0464      }
 465    }
 466
 467    /// <summary>
 468    /// Get minimum Zip feature version required to extract this entry
 469    /// </summary>
 470    /// <remarks>
 471    /// Minimum features are defined as:<br/>
 472    /// 1.0 - Default value<br/>
 473    /// 1.1 - File is a volume label<br/>
 474    /// 2.0 - File is a folder/directory<br/>
 475    /// 2.0 - File is compressed using Deflate compression<br/>
 476    /// 2.0 - File is encrypted using traditional encryption<br/>
 477    /// 2.1 - File is compressed using Deflate64<br/>
 478    /// 2.5 - File is compressed using PKWARE DCL Implode<br/>
 479    /// 2.7 - File is a patch data set<br/>
 480    /// 4.5 - File uses Zip64 format extensions<br/>
 481    /// 4.6 - File is compressed using BZIP2 compression<br/>
 482    /// 5.0 - File is encrypted using DES<br/>
 483    /// 5.0 - File is encrypted using 3DES<br/>
 484    /// 5.0 - File is encrypted using original RC2 encryption<br/>
 485    /// 5.0 - File is encrypted using RC4 encryption<br/>
 486    /// 5.1 - File is encrypted using AES encryption<br/>
 487    /// 5.1 - File is encrypted using corrected RC2 encryption<br/>
 488    /// 5.1 - File is encrypted using corrected RC2-64 encryption<br/>
 489    /// 6.1 - File is encrypted using non-OAEP key wrapping<br/>
 490    /// 6.2 - Central directory encryption (not confirmed yet)<br/>
 491    /// 6.3 - File is compressed using LZMA<br/>
 492    /// 6.3 - File is compressed using PPMD+<br/>
 493    /// 6.3 - File is encrypted using Blowfish<br/>
 494    /// 6.3 - File is encrypted using Twofish<br/>
 495    /// </remarks>
 496    /// <seealso cref="CanDecompress"></seealso>
 497    public int Version {
 498      get {
 499        // Return recorded version if known.
 198066500         if (versionToExtract != 0) {
 66394501          return versionToExtract & 0x00ff;               // Only lower order byte. High order is O/S file system.
 502        } else {
 131672503          int result = 10;
 131672504           if (AESKeySize > 0) {
 0505            result = ZipConstants.VERSION_AES;          // Ver 5.1 = AES
 131672506           } else if (CentralHeaderRequiresZip64) {
 247507            result = ZipConstants.VersionZip64;
 131672508           } else if (CompressionMethod.Deflated == method) {
 321509            result = 20;
 131425510           } else if (IsDirectory == true) {
 0511            result = 20;
 131104512           } else if (IsCrypted == true) {
 0513            result = 20;
 131104514           } else if (HasDosAttributes(0x08)) {
 0515            result = 11;
 516          }
 131672517          return result;
 518        }
 519      }
 520    }
 521
 522    /// <summary>
 523    /// Get a value indicating whether this entry can be decompressed by the library.
 524    /// </summary>
 525    /// <remarks>This is based on the <see cref="Version"></see> and
 526    /// wether the <see cref="IsCompressionMethodSupported()">compression method</see> is supported.</remarks>
 527    public bool CanDecompress {
 528      get {
 73529         return (Version <= ZipConstants.VersionMadeBy) &&
 73530          ((Version == 10) ||
 73531          (Version == 11) ||
 73532          (Version == 20) ||
 73533          (Version == 45) ||
 73534          (Version == 51)) &&
 73535          IsCompressionMethodSupported();
 536      }
 537    }
 538
 539    /// <summary>
 540    /// Force this entry to be recorded using Zip64 extensions.
 541    /// </summary>
 542    public void ForceZip64()
 543    {
 124544      forceZip64_ = true;
 124545    }
 546
 547    /// <summary>
 548    /// Get a value indicating wether Zip64 extensions were forced.
 549    /// </summary>
 550    /// <returns>A <see cref="bool"/> value of true if Zip64 extensions have been forced on; false if not.</returns>
 551    public bool IsZip64Forced()
 552    {
 132042553      return forceZip64_;
 554    }
 555
 556    /// <summary>
 557    /// Gets a value indicating if the entry requires Zip64 extensions
 558    /// to store the full entry values.
 559    /// </summary>
 560    /// <value>A <see cref="bool"/> value of true if a local header requires Zip64 extensions; false if not.</value>
 561    public bool LocalHeaderRequiresZip64 {
 562      get {
 395536563        bool result = forceZip64_;
 564
 395536565         if (!result) {
 394651566          ulong trueCompressedSize = compressedSize;
 567
 394651568           if ((versionToExtract == 0) && IsCrypted) {
 68569            trueCompressedSize += ZipConstants.CryptoHeaderSize;
 570          }
 571
 572          // TODO: A better estimation of the true limit based on compression overhead should be used
 573          // to determine when an entry should use Zip64.
 394651574          result =
 394651575            ((this.size >= uint.MaxValue) || (trueCompressedSize >= uint.MaxValue)) &&
 394651576            ((versionToExtract == 0) || (versionToExtract >= ZipConstants.VersionZip64));
 577        }
 578
 395536579        return result;
 580      }
 581    }
 582
 583    /// <summary>
 584    /// Get a value indicating wether the central directory entry requires Zip64 extensions to be stored.
 585    /// </summary>
 586    public bool CentralHeaderRequiresZip64 {
 587      get {
 197572588        return LocalHeaderRequiresZip64 || (offset >= uint.MaxValue);
 589      }
 590    }
 591
 592    /// <summary>
 593    /// Get/Set DosTime value.
 594    /// </summary>
 595    /// <remarks>
 596    /// The MS-DOS date format can only represent dates between 1/1/1980 and 12/31/2107.
 597    /// </remarks>
 598    public long DosTime {
 599      get {
 131812600         if ((known & Known.Time) == 0) {
 0601          return 0;
 602        } else {
 131812603          return dosTime;
 604        }
 605      }
 606
 607      set {
 608        unchecked {
 197925609          dosTime = (uint)value;
 610        }
 611
 197925612        known |= Known.Time;
 197925613      }
 614    }
 615
 616    /// <summary>
 617    /// Gets/Sets the time of last modification of the entry.
 618    /// </summary>
 619    /// <remarks>
 620    /// The <see cref="DosTime"></see> property is updated to match this as far as possible.
 621    /// </remarks>
 622    public DateTime DateTime
 623    {
 2624      get { return dateTime; }
 625
 626      set {
 131886627        var year = (uint)value.Year;
 131886628        var month = (uint)value.Month;
 131886629        var day = (uint)value.Day;
 131886630        var hour = (uint)value.Hour;
 131886631        var minute = (uint)value.Minute;
 131886632        var second = (uint)value.Second;
 633
 131886634         if (year < 1980) {
 0635          year = 1980;
 0636          month = 1;
 0637          day = 1;
 0638          hour = 0;
 0639          minute = 0;
 0640          second = 0;
 131886641         } else if (year > 2107) {
 0642          year = 2107;
 0643          month = 12;
 0644          day = 31;
 0645          hour = 23;
 0646          minute = 59;
 0647          second = 59;
 648        }
 649
 131886650        DosTime = ((year - 1980) & 0x7f) << 25 |
 131886651          (month << 21) |
 131886652          (day << 16) |
 131886653          (hour << 11) |
 131886654          (minute << 5) |
 131886655          (second >> 1);
 131886656      }
 657    }
 658
 659    /// <summary>
 660    /// Returns the entry name.
 661    /// </summary>
 662    /// <remarks>
 663    /// The unix naming convention is followed.
 664    /// Path components in the entry should always separated by forward slashes ('/').
 665    /// Dos device names like C: should also be removed.
 666    /// See the <see cref="ZipNameTransform"/> class, or <see cref="CleanName(string)"/>
 667    ///</remarks>
 668    public string Name {
 669      get {
 527086670        return name;
 671      }
 672    }
 673
 674    /// <summary>
 675    /// Gets/Sets the size of the uncompressed data.
 676    /// </summary>
 677    /// <returns>
 678    /// The size or -1 if unknown.
 679    /// </returns>
 680    /// <remarks>Setting the size before adding an entry to an archive can help
 681    /// avoid compatability problems with some archivers which dont understand Zip64 extensions.</remarks>
 682    public long Size {
 683      get {
 593205684         return (known & Known.Size) != 0 ? (long)size : -1L;
 685      }
 686      set {
 131877687        this.size = (ulong)value;
 131877688        this.known |= Known.Size;
 131877689      }
 690    }
 691
 692    /// <summary>
 693    /// Gets/Sets the size of the compressed data.
 694    /// </summary>
 695    /// <returns>
 696    /// The compressed entry size or -1 if unknown.
 697    /// </returns>
 698    public long CompressedSize {
 699      get {
 462089700         return (known & Known.CompressedSize) != 0 ? (long)compressedSize : -1L;
 701      }
 702      set {
 262984703        this.compressedSize = (ulong)value;
 262984704        this.known |= Known.CompressedSize;
 262984705      }
 706    }
 707
 708    /// <summary>
 709    /// Gets/Sets the crc of the uncompressed data.
 710    /// </summary>
 711    /// <exception cref="System.ArgumentOutOfRangeException">
 712    /// Crc is not in the range 0..0xffffffffL
 713    /// </exception>
 714    /// <returns>
 715    /// The crc value or -1 if unknown.
 716    /// </returns>
 717    public long Crc {
 718      get {
 329635719         return (known & Known.Crc) != 0 ? crc & 0xffffffffL : -1L;
 720      }
 721      set {
 131852722         if (((ulong)crc & 0xffffffff00000000L) != 0) {
 0723          throw new ArgumentOutOfRangeException(nameof(value));
 724        }
 131852725        this.crc = (uint)value;
 131852726        this.known |= Known.Crc;
 131852727      }
 728    }
 729
 730    /// <summary>
 731    /// Gets/Sets the compression method. Only Deflated and Stored are supported.
 732    /// </summary>
 733    /// <returns>
 734    /// The compression method for this entry
 735    /// </returns>
 736    /// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Deflated"/>
 737    /// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Stored"/>
 738    public CompressionMethod CompressionMethod {
 739      get {
 461414740        return method;
 741      }
 742
 743      set {
 65837744         if (!IsCompressionMethodSupported(value)) {
 1745          throw new NotSupportedException("Compression method not supported");
 746        }
 65836747        this.method = value;
 65836748      }
 749    }
 750
 751    /// <summary>
 752    /// Gets the compression method for outputting to the local or central header.
 753    /// Returns same value as CompressionMethod except when AES encrypting, which
 754    /// places 99 in the method and places the real method in the extra data.
 755    /// </summary>
 756    internal CompressionMethod CompressionMethodForHeader {
 757      get {
 257758         return (AESKeySize > 0) ? CompressionMethod.WinZipAES : method;
 759      }
 760    }
 761
 762    /// <summary>
 763    /// Gets/Sets the extra data.
 764    /// </summary>
 765    /// <exception cref="System.ArgumentOutOfRangeException">
 766    /// Extra data is longer than 64KB (0xffff) bytes.
 767    /// </exception>
 768    /// <returns>
 769    /// Extra data or null if not set.
 770    /// </returns>
 771    public byte[] ExtraData {
 772
 773      get {
 774        // TODO: This is slightly safer but less efficient.  Think about wether it should change.
 775        //        return (byte[]) extra.Clone();
 263288776        return extra;
 777      }
 778
 779      set {
 65874780         if (value == null) {
 0781          extra = null;
 0782        } else {
 65874783           if (value.Length > 0xffff) {
 0784            throw new System.ArgumentOutOfRangeException(nameof(value));
 785          }
 786
 65874787          extra = new byte[value.Length];
 65874788          Array.Copy(value, 0, extra, 0, value.Length);
 789        }
 65874790      }
 791    }
 792
 793
 794    /// <summary>
 795    /// For AES encrypted files returns or sets the number of bits of encryption (128, 192 or 256).
 796    /// When setting, only 0 (off), 128 or 256 is supported.
 797    /// </summary>
 798    public int AESKeySize {
 799      get {
 800        // the strength (1 or 3) is in the entry header
 132508801         switch (_aesEncryptionStrength) {
 802          case 0:
 132508803            return 0;   // Not AES
 804          case 1:
 0805            return 128;
 806          case 2:
 0807            return 192; // Not used by WinZip
 808          case 3:
 0809            return 256;
 810          default:
 0811            throw new ZipException("Invalid AESEncryptionStrength " + _aesEncryptionStrength);
 812        }
 813      }
 814      set {
 0815         switch (value) {
 816          case 0:
 0817            _aesEncryptionStrength = 0;
 0818            break;
 819          case 128:
 0820            _aesEncryptionStrength = 1;
 0821            break;
 822          case 256:
 0823            _aesEncryptionStrength = 3;
 0824            break;
 825          default:
 0826            throw new ZipException("AESKeySize must be 0, 128 or 256: " + value);
 827        }
 828      }
 829    }
 830
 831    /// <summary>
 832    /// AES Encryption strength for storage in extra data in entry header.
 833    /// 1 is 128 bit, 2 is 192 bit, 3 is 256 bit.
 834    /// </summary>
 835    internal byte AESEncryptionStrength {
 836      get {
 0837        return (byte)_aesEncryptionStrength;
 838      }
 839    }
 840
 841    /// <summary>
 842    /// Returns the length of the salt, in bytes
 843    /// </summary>
 844    internal int AESSaltLen {
 845      get {
 846        // Key size -> Salt length: 128 bits = 8 bytes, 192 bits = 12 bytes, 256 bits = 16 bytes.
 0847        return AESKeySize / 16;
 848      }
 849    }
 850
 851    /// <summary>
 852    /// Number of extra bytes required to hold the AES Header fields (Salt, Pwd verify, AuthCode)
 853    /// </summary>
 854    internal int AESOverheadSize {
 855      get {
 856        // File format:
 857        //   Bytes    Content
 858        // Variable    Salt value
 859        //     2    Password verification value
 860        // Variable    Encrypted file data
 861        //    10    Authentication code
 0862        return 12 + AESSaltLen;
 863      }
 864    }
 865
 866    /// <summary>
 867    /// Process extra data fields updating the entry based on the contents.
 868    /// </summary>
 869    /// <param name="localHeader">True if the extra data fields should be handled
 870    /// for a local header, rather than for a central header.
 871    /// </param>
 872    internal void ProcessExtraData(bool localHeader)
 873    {
 66037874      var extraData = new ZipExtraData(this.extra);
 875
 66037876       if (extraData.Find(0x0001)) {
 877        // Version required to extract is ignored here as some archivers dont set it correctly
 878        // in theory it should be version 45 or higher
 879
 880        // The recorded size will change but remember that this is zip64.
 123881        forceZip64_ = true;
 882
 123883         if (extraData.ValueLength < 4) {
 0884          throw new ZipException("Extra data extended Zip64 information length is invalid");
 885        }
 886
 887        // (localHeader ||) was deleted, because actually there is no specific difference with reading sizes between loc
 888        // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
 889        // ...
 890        // 4.4  Explanation of fields
 891        // ...
 892        //  4.4.8 compressed size: (4 bytes)
 893        //  4.4.9 uncompressed size: (4 bytes)
 894        //
 895        //    The size of the file compressed (4.4.8) and uncompressed,
 896        //    (4.4.9) respectively.  When a decryption header is present it
 897        //    will be placed in front of the file data and the value of the
 898        //    compressed file size will include the bytes of the decryption
 899        //    header.  If bit 3 of the general purpose bit flag is set,
 900        //    these fields are set to zero in the local header and the
 901        //    correct values are put in the data descriptor and
 902        //    in the central directory.  If an archive is in ZIP64 format
 903        //    and the value in this field is 0xFFFFFFFF, the size will be
 904        //    in the corresponding 8 byte ZIP64 extended information
 905        //    extra field.  When encrypting the central directory, if the
 906        //    local header is not in ZIP64 format and general purpose bit
 907        //    flag 13 is set indicating masking, the value stored for the
 908        //    uncompressed size in the Local Header will be zero.
 909        //
 910        // Othewise there is problem with minizip implementation
 123911         if (size == uint.MaxValue) {
 123912          size = (ulong)extraData.ReadLong();
 913        }
 914
 123915         if (compressedSize == uint.MaxValue) {
 123916          compressedSize = (ulong)extraData.ReadLong();
 917        }
 918
 123919         if (!localHeader && (offset == uint.MaxValue)) {
 0920          offset = extraData.ReadLong();
 921        }
 922
 923        // Disk number on which file starts is ignored
 0924      } else {
 65914925         if (
 65914926          ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
 65914927          ((size == uint.MaxValue) || (compressedSize == uint.MaxValue))
 65914928        ) {
 0929          throw new ZipException("Zip64 Extended information required but is missing.");
 930        }
 931      }
 932
 66037933      dateTime = GetDateTime(extraData);
 66037934       if (method == CompressionMethod.WinZipAES) {
 0935        ProcessAESExtraData(extraData);
 936      }
 66037937    }
 938
 939    private DateTime GetDateTime(ZipExtraData extraData) {
 940      // Check for NT timestamp
 941            // NOTE: Disable by default to match behavior of InfoZIP
 942#if RESPECT_NT_TIMESTAMP
 943      NTTaggedData ntData = extraData.GetData<NTTaggedData>();
 944      if (ntData != null)
 945        return ntData.LastModificationTime;
 946#endif
 947
 948      // Check for Unix timestamp
 66037949      ExtendedUnixData unixData = extraData.GetData<ExtendedUnixData>();
 66037950       if (unixData != null &&
 66037951        // Only apply modification time, but require all other values to be present
 66037952        // This is done to match InfoZIP's behaviour
 66037953        ((unixData.Include & ExtendedUnixData.Flags.ModificationTime) != 0) &&
 66037954        ((unixData.Include & ExtendedUnixData.Flags.AccessTime) != 0) &&
 66037955        ((unixData.Include & ExtendedUnixData.Flags.CreateTime) != 0))
 0956        return unixData.ModificationTime;
 957
 958      // Fall back to DOS time
 66037959      uint sec = Math.Min(59, 2 * (dosTime & 0x1f));
 66037960      uint min = Math.Min(59, (dosTime >> 5) & 0x3f);
 66037961      uint hrs = Math.Min(23, (dosTime >> 11) & 0x1f);
 66037962      uint mon = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf)));
 66037963      uint year = ((dosTime >> 25) & 0x7f) + 1980;
 66037964      int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f)));
 66037965      return new DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec, DateTimeKind.Utc);
 966    }
 967
 968    // For AES the method in the entry is 99, and the real compression method is in the extradata
 969    //
 970    private void ProcessAESExtraData(ZipExtraData extraData)
 971    {
 972
 0973       if (extraData.Find(0x9901)) {
 974        // Set version and flag for Zipfile.CreateAndInitDecryptionStream
 0975        versionToExtract = ZipConstants.VERSION_AES;            // Ver 5.1 = AES see "Version" getter
 976                                    // Set StrongEncryption flag for ZipFile.CreateAndInitDecryptionStream
 0977        Flags = Flags | (int)GeneralBitFlags.StrongEncryption;
 978        //
 979        // Unpack AES extra data field see http://www.winzip.com/aes_info.htm
 0980        int length = extraData.ValueLength;         // Data size currently 7
 0981         if (length < 7)
 0982          throw new ZipException("AES Extra Data Length " + length + " invalid.");
 0983        int ver = extraData.ReadShort();            // Version number (1=AE-1 2=AE-2)
 0984        int vendorId = extraData.ReadShort();       // 2-character vendor ID 0x4541 = "AE"
 0985        int encrStrength = extraData.ReadByte();    // encryption strength 1 = 128 2 = 192 3 = 256
 0986        int actualCompress = extraData.ReadShort(); // The actual compression method used to compress the file
 0987        _aesVer = ver;
 0988        _aesEncryptionStrength = encrStrength;
 0989        method = (CompressionMethod)actualCompress;
 0990      } else
 0991        throw new ZipException("AES Extra Data missing");
 992    }
 993
 994    /// <summary>
 995    /// Gets/Sets the entry comment.
 996    /// </summary>
 997    /// <exception cref="System.ArgumentOutOfRangeException">
 998    /// If comment is longer than 0xffff.
 999    /// </exception>
 1000    /// <returns>
 1001    /// The comment or null if not set.
 1002    /// </returns>
 1003    /// <remarks>
 1004    /// A comment is only available for entries when read via the <see cref="ZipFile"/> class.
 1005    /// The <see cref="ZipInputStream"/> class doesnt have the comment data available.
 1006    /// </remarks>
 1007    public string Comment {
 1008      get {
 1316731009        return comment;
 1010      }
 1011      set {
 1012        // This test is strictly incorrect as the length is in characters
 1013        // while the storage limit is in bytes.
 1014        // While the test is partially correct in that a comment of this length or greater
 1015        // is definitely invalid, shorter comments may also have an invalid length
 1016        // where there are multi-byte characters
 1017        // The full test is not possible here however as the code page to apply conversions with
 1018        // isnt available.
 31019         if ((value != null) && (value.Length > 0xffff)) {
 01020          throw new ArgumentOutOfRangeException(nameof(value), "cannot exceed 65535");
 1021        }
 1022
 31023        comment = value;
 31024      }
 1025    }
 1026
 1027    /// <summary>
 1028    /// Gets a value indicating if the entry is a directory.
 1029    /// however.
 1030    /// </summary>
 1031    /// <remarks>
 1032    /// A directory is determined by an entry name with a trailing slash '/'.
 1033    /// The external file attributes can also indicate an entry is for a directory.
 1034    /// Currently only dos/windows attributes are tested in this manner.
 1035    /// The trailing slash convention should always be followed.
 1036    /// </remarks>
 1037    public bool IsDirectory {
 1038      get {
 5263341039        int nameLength = name.Length;
 5263341040        bool result =
 5263341041          ((nameLength > 0) &&
 5263341042          ((name[nameLength - 1] == '/') || (name[nameLength - 1] == '\\'))) ||
 5263341043          HasDosAttributes(16)
 5263341044          ;
 271045        return result;
 1046      }
 1047    }
 1048
 1049    /// <summary>
 1050    /// Get a value of true if the entry appears to be a file; false otherwise
 1051    /// </summary>
 1052    /// <remarks>
 1053    /// This only takes account of DOS/Windows attributes.  Other operating systems are ignored.
 1054    /// For linux and others the result may be incorrect.
 1055    /// </remarks>
 1056    public bool IsFile {
 1057      get {
 2634861058        return !IsDirectory && !HasDosAttributes(8);
 1059      }
 1060    }
 1061
 1062    /// <summary>
 1063    /// Test entry to see if data can be extracted.
 1064    /// </summary>
 1065    /// <returns>Returns true if data can be extracted for this entry; false otherwise.</returns>
 1066    public bool IsCompressionMethodSupported()
 1067    {
 1320121068      return IsCompressionMethodSupported(CompressionMethod);
 1069    }
 1070
 1071    #region ICloneable Members
 1072    /// <summary>
 1073    /// Creates a copy of this zip entry.
 1074    /// </summary>
 1075    /// <returns>An <see cref="Object"/> that is a copy of the current instance.</returns>
 1076    public object Clone()
 1077    {
 4610931078      var result = (ZipEntry)this.MemberwiseClone();
 1079
 1080      // Ensure extra data is unique if it exists.
 4610931081       if (extra != null) {
 721082        result.extra = new byte[extra.Length];
 721083        Array.Copy(extra, 0, result.extra, 0, extra.Length);
 1084      }
 1085
 4610931086      return result;
 1087    }
 1088
 1089    #endregion
 1090
 1091    /// <summary>
 1092    /// Gets a string representation of this ZipEntry.
 1093    /// </summary>
 1094    /// <returns>A readable textual representation of this <see cref="ZipEntry"/></returns>
 1095    public override string ToString()
 1096    {
 01097      return name;
 1098    }
 1099
 1100    /// <summary>
 1101    /// Test a <see cref="CompressionMethod">compression method</see> to see if this library
 1102    /// supports extracting data compressed with that method
 1103    /// </summary>
 1104    /// <param name="method">The compression method to test.</param>
 1105    /// <returns>Returns true if the compression method is supported; false otherwise</returns>
 1106    public static bool IsCompressionMethodSupported(CompressionMethod method)
 1107    {
 1978491108      return
 1978491109        (method == CompressionMethod.Deflated) ||
 1978491110        (method == CompressionMethod.Stored);
 1111    }
 1112
 1113    /// <summary>
 1114    /// Cleans a name making it conform to Zip file conventions.
 1115    /// Devices names ('c:\') and UNC share names ('\\server\share') are removed
 1116    /// and forward slashes ('\') are converted to back slashes ('/').
 1117    /// Names are made relative by trimming leading slashes which is compatible
 1118    /// with the ZIP naming convention.
 1119    /// </summary>
 1120    /// <param name="name">The name to clean</param>
 1121    /// <returns>The 'cleaned' name.</returns>
 1122    /// <remarks>
 1123    /// The <seealso cref="ZipNameTransform">Zip name transform</seealso> class is more flexible.
 1124    /// </remarks>
 1125    public static string CleanName(string name)
 1126    {
 1318771127       if (name == null) {
 01128        return string.Empty;
 1129      }
 1130
 1318771131       if (Path.IsPathRooted(name)) {
 1132        // NOTE:
 1133        // for UNC names...  \\machine\share\zoom\beet.txt gives \zoom\beet.txt
 01134        name = name.Substring(Path.GetPathRoot(name).Length);
 1135      }
 1136
 1318771137      name = name.Replace(@"\", "/");
 1138
 1318771139       while ((name.Length > 0) && (name[0] == '/')) {
 01140        name = name.Remove(0, 1);
 1141      }
 1318771142      return name;
 1143    }
 1144
 1145    #region Instance Fields
 1146    Known known;
 1318791147    int externalFileAttributes = -1;     // contains external attributes (O/S dependant)
 1148
 1149    ushort versionMadeBy;                   // Contains host system and version information
 1150                        // only relevant for central header entries
 1151
 1152    string name;
 1153    ulong size;
 1154    ulong compressedSize;
 1155    ushort versionToExtract;                // Version required to extract (library handles <= 2.0)
 1156    uint crc;
 1157    uint dosTime;
 1158    DateTime dateTime;
 1159
 1318791160    CompressionMethod method = CompressionMethod.Deflated;
 1161    byte[] extra;
 1162    string comment;
 1163
 1164    int flags;                             // general purpose bit flags
 1165
 1318791166    long zipFileIndex = -1;                // used by ZipFile
 1167    long offset;                           // used by ZipFile and ZipOutputStream
 1168
 1169    bool forceZip64_;
 1170    byte cryptoCheckValue_;
 1171    int _aesVer;                            // Version number (2 = AE-2 ?). Assigned but not used.
 1172    int _aesEncryptionStrength;             // Encryption strength 1 = 128 2 = 192 3 = 256
 1173    #endregion
 1174  }
 1175}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipEntryFactory.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipEntryFactory.htm new file mode 100644 index 000000000..514410af1 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipEntryFactory.htm @@ -0,0 +1,390 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipEntryFactory - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipEntryFactory
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipEntryFactory.cs
Covered lines:51
Uncovered lines:50
Coverable lines:101
Total lines:341
Line coverage:50.4%
Branch coverage:35%
+

Metrics

+ + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
.ctor(...)1100100
.ctor(...)1100100
MakeFileEntry(...)1100100
MakeFileEntry(...)1100100
MakeFileEntry(...)1661.7661.90
MakeDirectoryEntry(...)100
MakeDirectoryEntry(...)1300
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipEntryFactory.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using ICSharpCode.SharpZipLib.Core;
 4
 5namespace ICSharpCode.SharpZipLib.Zip
 6{
 7  /// <summary>
 8  /// Basic implementation of <see cref="IEntryFactory"></see>
 9  /// </summary>
 10  public class ZipEntryFactory : IEntryFactory
 11  {
 12    #region Enumerations
 13    /// <summary>
 14    /// Defines the possible values to be used for the <see cref="ZipEntry.DateTime"/>.
 15    /// </summary>
 16    public enum TimeSetting
 17    {
 18      /// <summary>
 19      /// Use the recorded LastWriteTime value for the file.
 20      /// </summary>
 21      LastWriteTime,
 22      /// <summary>
 23      /// Use the recorded LastWriteTimeUtc value for the file
 24      /// </summary>
 25      LastWriteTimeUtc,
 26      /// <summary>
 27      /// Use the recorded CreateTime value for the file.
 28      /// </summary>
 29      CreateTime,
 30      /// <summary>
 31      /// Use the recorded CreateTimeUtc value for the file.
 32      /// </summary>
 33      CreateTimeUtc,
 34      /// <summary>
 35      /// Use the recorded LastAccessTime value for the file.
 36      /// </summary>
 37      LastAccessTime,
 38      /// <summary>
 39      /// Use the recorded LastAccessTimeUtc value for the file.
 40      /// </summary>
 41      LastAccessTimeUtc,
 42      /// <summary>
 43      /// Use a fixed value.
 44      /// </summary>
 45      /// <remarks>The actual <see cref="DateTime"/> value used can be
 46      /// specified via the <see cref="ZipEntryFactory(DateTime)"/> constructor or
 47      /// using the <see cref="ZipEntryFactory(TimeSetting)"/> with the setting set
 48      /// to <see cref="TimeSetting.Fixed"/> which will use the <see cref="DateTime"/> when this class was constructed.
 49      /// The <see cref="FixedDateTime"/> property can also be used to set this value.</remarks>
 50      Fixed,
 51    }
 52    #endregion
 53
 54    #region Constructors
 55    /// <summary>
 56    /// Initialise a new instance of the <see cref="ZipEntryFactory"/> class.
 57    /// </summary>
 58    /// <remarks>A default <see cref="INameTransform"/>, and the LastWriteTime for files is used.</remarks>
 9559    public ZipEntryFactory()
 60    {
 9561      nameTransform_ = new ZipNameTransform();
 9562    }
 63
 64    /// <summary>
 65    /// Initialise a new instance of <see cref="ZipEntryFactory"/> using the specified <see cref="TimeSetting"/>
 66    /// </summary>
 67    /// <param name="timeSetting">The <see cref="TimeSetting">time setting</see> to use when creating <see cref="ZipEntr
 168    public ZipEntryFactory(TimeSetting timeSetting)
 69    {
 170      timeSetting_ = timeSetting;
 171      nameTransform_ = new ZipNameTransform();
 172    }
 73
 74    /// <summary>
 75    /// Initialise a new instance of <see cref="ZipEntryFactory"/> using the specified <see cref="DateTime"/>
 76    /// </summary>
 77    /// <param name="time">The time to set all <see cref="ZipEntry.DateTime"/> values to.</param>
 178    public ZipEntryFactory(DateTime time)
 79    {
 180      timeSetting_ = TimeSetting.Fixed;
 181      FixedDateTime = time;
 182      nameTransform_ = new ZipNameTransform();
 183    }
 84
 85    #endregion
 86
 87    #region Properties
 88    /// <summary>
 89    /// Get / set the <see cref="INameTransform"/> to be used when creating new <see cref="ZipEntry"/> values.
 90    /// </summary>
 91    /// <remarks>
 92    /// Setting this property to null will cause a default <see cref="ZipNameTransform">name transform</see> to be used.
 93    /// </remarks>
 94    public INameTransform NameTransform {
 6574395      get { return nameTransform_; }
 96      set {
 497         if (value == null) {
 098          nameTransform_ = new ZipNameTransform();
 099        } else {
 4100          nameTransform_ = value;
 101        }
 4102      }
 103    }
 104
 105    /// <summary>
 106    /// Get / set the <see cref="TimeSetting"/> in use.
 107    /// </summary>
 108    public TimeSetting Setting {
 3109      get { return timeSetting_; }
 2110      set { timeSetting_ = value; }
 111    }
 112
 113    /// <summary>
 114    /// Get / set the <see cref="DateTime"/> value to use when <see cref="Setting"/> is set to <see cref="TimeSetting.Fi
 115    /// </summary>
 116    public DateTime FixedDateTime {
 5117      get { return fixedDateTime_; }
 118      set {
 2119         if (value.Year < 1970) {
 0120          throw new ArgumentException("Value is too old to be valid", nameof(value));
 121        }
 2122        fixedDateTime_ = value;
 2123      }
 124    }
 125
 126    /// <summary>
 127    /// A bitmask defining the attributes to be retrieved from the actual file.
 128    /// </summary>
 129    /// <remarks>The default is to get all possible attributes from the actual file.</remarks>
 130    public int GetAttributes {
 3131      get { return getAttributes_; }
 0132      set { getAttributes_ = value; }
 133    }
 134
 135    /// <summary>
 136    /// A bitmask defining which attributes are to be set on.
 137    /// </summary>
 138    /// <remarks>By default no attributes are set on.</remarks>
 139    public int SetAttributes {
 3140      get { return setAttributes_; }
 2141      set { setAttributes_ = value; }
 142    }
 143
 144    /// <summary>
 145    /// Get set a value indicating wether unidoce text should be set on.
 146    /// </summary>
 147    public bool IsUnicodeText {
 0148      get { return isUnicodeText_; }
 4149      set { isUnicodeText_ = value; }
 150    }
 151
 152    #endregion
 153
 154    #region IEntryFactory Members
 155
 156    /// <summary>
 157    /// Make a new <see cref="ZipEntry"/> for a file.
 158    /// </summary>
 159    /// <param name="fileName">The name of the file to create a new entry for.</param>
 160    /// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>
 161    public ZipEntry MakeFileEntry(string fileName)
 162    {
 7163      return MakeFileEntry(fileName, null, true);
 164    }
 165
 166    /// <summary>
 167    /// Make a new <see cref="ZipEntry"/> for a file.
 168    /// </summary>
 169    /// <param name="fileName">The name of the file to create a new entry for.</param>
 170    /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
 171    /// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>
 172    public ZipEntry MakeFileEntry(string fileName, bool useFileSystem)
 173    {
 165174      return MakeFileEntry(fileName, null, useFileSystem);
 175    }
 176
 177    /// <summary>
 178    /// Make a new <see cref="ZipEntry"/> from a name.
 179    /// </summary>
 180    /// <param name="fileName">The name of the file to create a new entry for.</param>
 181    /// <param name="entryName">An alternative name to be used for the new entry. Null if not applicable.</param>
 182    /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
 183    /// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>
 184    public ZipEntry MakeFileEntry(string fileName, string entryName, bool useFileSystem)
 185    {
 172186       var result = new ZipEntry(nameTransform_.TransformFile(!string.IsNullOrEmpty(entryName) ? entryName : fileName));
 172187      result.IsUnicodeText = isUnicodeText_;
 188
 172189      int externalAttributes = 0;
 172190      bool useAttributes = (setAttributes_ != 0);
 191
 172192      FileInfo fi = null;
 172193       if (useFileSystem) {
 7194        fi = new FileInfo(fileName);
 195      }
 196
 172197       if ((fi != null) && fi.Exists) {
 7198         switch (timeSetting_) {
 199          case TimeSetting.CreateTime:
 0200            result.DateTime = fi.CreationTime;
 0201            break;
 202
 203          case TimeSetting.CreateTimeUtc:
 0204            result.DateTime = fi.CreationTimeUtc;
 0205            break;
 206
 207          case TimeSetting.LastAccessTime:
 0208            result.DateTime = fi.LastAccessTime;
 0209            break;
 210
 211          case TimeSetting.LastAccessTimeUtc:
 0212            result.DateTime = fi.LastAccessTimeUtc;
 0213            break;
 214
 215          case TimeSetting.LastWriteTime:
 7216            result.DateTime = fi.LastWriteTime;
 7217            break;
 218
 219          case TimeSetting.LastWriteTimeUtc:
 0220            result.DateTime = fi.LastWriteTimeUtc;
 0221            break;
 222
 223          case TimeSetting.Fixed:
 0224            result.DateTime = fixedDateTime_;
 0225            break;
 226
 227          default:
 0228            throw new ZipException("Unhandled time setting in MakeFileEntry");
 229        }
 230
 7231        result.Size = fi.Length;
 232
 7233        useAttributes = true;
 7234        externalAttributes = ((int)fi.Attributes & getAttributes_);
 7235      } else {
 165236         if (timeSetting_ == TimeSetting.Fixed) {
 2237          result.DateTime = fixedDateTime_;
 238        }
 239      }
 240
 172241       if (useAttributes) {
 9242        externalAttributes |= setAttributes_;
 9243        result.ExternalFileAttributes = externalAttributes;
 244      }
 245
 172246      return result;
 247    }
 248
 249    /// <summary>
 250    /// Make a new <see cref="ZipEntry"></see> for a directory.
 251    /// </summary>
 252    /// <param name="directoryName">The raw untransformed name for the new directory</param>
 253    /// <returns>Returns a new <see cref="ZipEntry"></see> representing a directory.</returns>
 254    public ZipEntry MakeDirectoryEntry(string directoryName)
 255    {
 0256      return MakeDirectoryEntry(directoryName, true);
 257    }
 258
 259    /// <summary>
 260    /// Make a new <see cref="ZipEntry"></see> for a directory.
 261    /// </summary>
 262    /// <param name="directoryName">The raw untransformed name for the new directory</param>
 263    /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
 264    /// <returns>Returns a new <see cref="ZipEntry"></see> representing a directory.</returns>
 265    public ZipEntry MakeDirectoryEntry(string directoryName, bool useFileSystem)
 266    {
 267
 0268      var result = new ZipEntry(nameTransform_.TransformDirectory(directoryName));
 0269      result.IsUnicodeText = isUnicodeText_;
 0270      result.Size = 0;
 271
 0272      int externalAttributes = 0;
 273
 0274      DirectoryInfo di = null;
 275
 0276       if (useFileSystem) {
 0277        di = new DirectoryInfo(directoryName);
 278      }
 279
 280
 0281       if ((di != null) && di.Exists) {
 0282         switch (timeSetting_) {
 283          case TimeSetting.CreateTime:
 0284            result.DateTime = di.CreationTime;
 0285            break;
 286
 287          case TimeSetting.CreateTimeUtc:
 0288            result.DateTime = di.CreationTimeUtc;
 0289            break;
 290
 291          case TimeSetting.LastAccessTime:
 0292            result.DateTime = di.LastAccessTime;
 0293            break;
 294
 295          case TimeSetting.LastAccessTimeUtc:
 0296            result.DateTime = di.LastAccessTimeUtc;
 0297            break;
 298
 299          case TimeSetting.LastWriteTime:
 0300            result.DateTime = di.LastWriteTime;
 0301            break;
 302
 303          case TimeSetting.LastWriteTimeUtc:
 0304            result.DateTime = di.LastWriteTimeUtc;
 0305            break;
 306
 307          case TimeSetting.Fixed:
 0308            result.DateTime = fixedDateTime_;
 0309            break;
 310
 311          default:
 0312            throw new ZipException("Unhandled time setting in MakeDirectoryEntry");
 313        }
 314
 0315        externalAttributes = ((int)di.Attributes & getAttributes_);
 0316      } else {
 0317         if (timeSetting_ == TimeSetting.Fixed) {
 0318          result.DateTime = fixedDateTime_;
 319        }
 320      }
 321
 322      // Always set directory attribute on.
 0323      externalAttributes |= (setAttributes_ | 16);
 0324      result.ExternalFileAttributes = externalAttributes;
 325
 0326      return result;
 327    }
 328
 329    #endregion
 330
 331    #region Instance Fields
 332    INameTransform nameTransform_;
 97333    DateTime fixedDateTime_ = DateTime.Now;
 334    TimeSetting timeSetting_;
 335    bool isUnicodeText_;
 336
 97337    int getAttributes_ = -1;
 338    int setAttributes_;
 339    #endregion
 340  }
 341}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipException.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipException.htm new file mode 100644 index 000000000..bcc7392a7 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipException.htm @@ -0,0 +1,92 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipException - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipException
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipException.cs
Covered lines:2
Uncovered lines:6
Coverable lines:8
Total lines:48
Line coverage:25%
+

Metrics

+ + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor()100
.ctor(...)1100100
.ctor(...)100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipException.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Runtime.Serialization;
 3
 4namespace ICSharpCode.SharpZipLib.Zip
 5{
 6  /// <summary>
 7  /// ZipException represents exceptions specific to Zip classes and code.
 8  /// </summary>
 9  [Serializable]
 10  public class ZipException : SharpZipBaseException
 11  {
 12    /// <summary>
 13    /// Deserialization constructor
 14    /// </summary>
 15    /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
 16    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
 17    protected ZipException(SerializationInfo info, StreamingContext context)
 018      : base(info, context)
 19    {
 020    }
 21
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="ZipException" />.
 24    /// </summary>
 025    public ZipException()
 26    {
 027    }
 28
 29    /// <summary>
 30    /// Initialise a new instance of <see cref="ZipException" /> with its message string.
 31    /// </summary>
 32    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 33    public ZipException(string message)
 1434      : base(message)
 35    {
 1436    }
 37
 38    /// <summary>
 39    /// Initialise a new instance of <see cref="ZipException" />.
 40    /// </summary>
 41    /// <param name="message">A <see cref="string"/> that describes the error.</param>
 42    /// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
 43    public ZipException(string message, Exception innerException)
 044      : base(message, innerException)
 45    {
 046    }
 47  }
 48}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipExtraData.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipExtraData.htm new file mode 100644 index 000000000..441e65890 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipExtraData.htm @@ -0,0 +1,963 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipExtraData - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipExtraData
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipExtraData.cs
Covered lines:121
Uncovered lines:19
Coverable lines:140
Total lines:896
Line coverage:86.4%
Branch coverage:67.2%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
.ctor(...)2100100
GetEntryData()266.6766.67
Clear()310060
GetStreamForTag(...)210066.67
GetData()26066.67
Find(...)6100100
AddEntry(...)200
AddEntry(...)89076.92
StartNewEntry()1100100
AddNewEntry(...)1100100
AddData(...)1100100
AddData(...)200
AddLeShort(...)1100100
AddLeInt(...)1100100
AddLeLong(...)1100100
Delete(...)2100100
ReadLong()1100100
ReadInt()1100100
ReadShort()1100100
ReadByte()3100100
Skip(...)1100100
ReadCheck(...)585.7177.78
ReadShortInternal()28066.67
SetShort(...)1100100
Dispose()200
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipExtraData.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Zip
 5{
 6  // TODO: Sort out wether tagged data is useful and what a good implementation might look like.
 7  // Its just a sketch of an idea at the moment.
 8
 9  /// <summary>
 10  /// ExtraData tagged value interface.
 11  /// </summary>
 12  public interface ITaggedData
 13  {
 14    /// <summary>
 15    /// Get the ID for this tagged data value.
 16    /// </summary>
 17    short TagID { get; }
 18
 19    /// <summary>
 20    /// Set the contents of this instance from the data passed.
 21    /// </summary>
 22    /// <param name="data">The data to extract contents from.</param>
 23    /// <param name="offset">The offset to begin extracting data from.</param>
 24    /// <param name="count">The number of bytes to extract.</param>
 25    void SetData(byte[] data, int offset, int count);
 26
 27    /// <summary>
 28    /// Get the data representing this instance.
 29    /// </summary>
 30    /// <returns>Returns the data for this instance.</returns>
 31    byte[] GetData();
 32  }
 33
 34  /// <summary>
 35  /// A raw binary tagged value
 36  /// </summary>
 37  public class RawTaggedData : ITaggedData
 38  {
 39    /// <summary>
 40    /// Initialise a new instance.
 41    /// </summary>
 42    /// <param name="tag">The tag ID.</param>
 43    public RawTaggedData(short tag)
 44    {
 45      _tag = tag;
 46    }
 47
 48    #region ITaggedData Members
 49
 50    /// <summary>
 51    /// Get the ID for this tagged data value.
 52    /// </summary>
 53    public short TagID {
 54      get { return _tag; }
 55      set { _tag = value; }
 56    }
 57
 58    /// <summary>
 59    /// Set the data from the raw values provided.
 60    /// </summary>
 61    /// <param name="data">The raw data to extract values from.</param>
 62    /// <param name="offset">The index to start extracting values from.</param>
 63    /// <param name="count">The number of bytes available.</param>
 64    public void SetData(byte[] data, int offset, int count)
 65    {
 66      if (data == null) {
 67        throw new ArgumentNullException(nameof(data));
 68      }
 69
 70      _data = new byte[count];
 71      Array.Copy(data, offset, _data, 0, count);
 72    }
 73
 74    /// <summary>
 75    /// Get the binary data representing this instance.
 76    /// </summary>
 77    /// <returns>The raw binary data representing this instance.</returns>
 78    public byte[] GetData()
 79    {
 80      return _data;
 81    }
 82
 83    #endregion
 84
 85    /// <summary>
 86    /// Get /set the binary data representing this instance.
 87    /// </summary>
 88    /// <returns>The raw binary data representing this instance.</returns>
 89    public byte[] Data {
 90      get { return _data; }
 91      set { _data = value; }
 92    }
 93
 94    #region Instance Fields
 95    /// <summary>
 96    /// The tag ID for this instance.
 97    /// </summary>
 98    short _tag;
 99
 100    byte[] _data;
 101    #endregion
 102  }
 103
 104  /// <summary>
 105  /// Class representing extended unix date time values.
 106  /// </summary>
 107  public class ExtendedUnixData : ITaggedData
 108  {
 109    /// <summary>
 110    /// Flags indicate which values are included in this instance.
 111    /// </summary>
 112    [Flags]
 113    public enum Flags : byte
 114    {
 115      /// <summary>
 116      /// The modification time is included
 117      /// </summary>
 118      ModificationTime = 0x01,
 119
 120      /// <summary>
 121      /// The access time is included
 122      /// </summary>
 123      AccessTime = 0x02,
 124
 125      /// <summary>
 126      /// The create time is included.
 127      /// </summary>
 128      CreateTime = 0x04,
 129    }
 130
 131    #region ITaggedData Members
 132
 133    /// <summary>
 134    /// Get the ID
 135    /// </summary>
 136    public short TagID {
 137      get { return 0x5455; }
 138    }
 139
 140    /// <summary>
 141    /// Set the data from the raw values provided.
 142    /// </summary>
 143    /// <param name="data">The raw data to extract values from.</param>
 144    /// <param name="index">The index to start extracting values from.</param>
 145    /// <param name="count">The number of bytes available.</param>
 146    public void SetData(byte[] data, int index, int count)
 147    {
 148      using (MemoryStream ms = new MemoryStream(data, index, count, false))
 149      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 150        // bit 0           if set, modification time is present
 151        // bit 1           if set, access time is present
 152        // bit 2           if set, creation time is present
 153
 154        _flags = (Flags)helperStream.ReadByte();
 155        if (((_flags & Flags.ModificationTime) != 0))
 156        {
 157          int iTime = helperStream.ReadLEInt();
 158
 159          _modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 160            new TimeSpan(0, 0, 0, iTime, 0);
 161
 162          // Central-header version is truncated after modification time
 163          if (count <= 5) return;
 164        }
 165
 166        if ((_flags & Flags.AccessTime) != 0) {
 167          int iTime = helperStream.ReadLEInt();
 168
 169          _lastAccessTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 170            new TimeSpan(0, 0, 0, iTime, 0);
 171        }
 172
 173        if ((_flags & Flags.CreateTime) != 0) {
 174          int iTime = helperStream.ReadLEInt();
 175
 176          _createTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
 177            new TimeSpan(0, 0, 0, iTime, 0);
 178        }
 179      }
 180    }
 181
 182    /// <summary>
 183    /// Get the binary data representing this instance.
 184    /// </summary>
 185    /// <returns>The raw binary data representing this instance.</returns>
 186    public byte[] GetData()
 187    {
 188      using (MemoryStream ms = new MemoryStream())
 189      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 190        helperStream.IsStreamOwner = false;
 191        helperStream.WriteByte((byte)_flags);     // Flags
 192        if ((_flags & Flags.ModificationTime) != 0) {
 193          TimeSpan span = _modificationTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 194          var seconds = (int)span.TotalSeconds;
 195          helperStream.WriteLEInt(seconds);
 196        }
 197        if ((_flags & Flags.AccessTime) != 0) {
 198          TimeSpan span = _lastAccessTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 199          var seconds = (int)span.TotalSeconds;
 200          helperStream.WriteLEInt(seconds);
 201        }
 202        if ((_flags & Flags.CreateTime) != 0) {
 203          TimeSpan span = _createTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 204          var seconds = (int)span.TotalSeconds;
 205          helperStream.WriteLEInt(seconds);
 206        }
 207        return ms.ToArray();
 208      }
 209    }
 210
 211    #endregion
 212
 213    /// <summary>
 214    /// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>
 215    /// </summary>
 216    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 217    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 218    /// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,
 219    /// which is the number of seconds since 1970-01-01.
 220    /// Being 32 bits means the values here cover a range of about 136 years.
 221    /// The minimum representable time is 1901-12-13 20:45:52,
 222    /// and the maximum representable time is 2038-01-19 03:14:07.
 223    /// </remarks>
 224    public static bool IsValidValue(DateTime value)
 225    {
 226      return ((value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||
 227          (value <= new DateTime(2038, 1, 19, 03, 14, 07)));
 228    }
 229
 230    /// <summary>
 231    /// Get /set the Modification Time
 232    /// </summary>
 233    /// <exception cref="ArgumentOutOfRangeException"></exception>
 234    /// <seealso cref="IsValidValue"></seealso>
 235    public DateTime ModificationTime {
 236      get { return _modificationTime; }
 237      set {
 238        if (!IsValidValue(value)) {
 239          throw new ArgumentOutOfRangeException(nameof(value));
 240        }
 241
 242        _flags |= Flags.ModificationTime;
 243        _modificationTime = value;
 244      }
 245    }
 246
 247    /// <summary>
 248    /// Get / set the Access Time
 249    /// </summary>
 250    /// <exception cref="ArgumentOutOfRangeException"></exception>
 251    /// <seealso cref="IsValidValue"></seealso>
 252    public DateTime AccessTime {
 253      get { return _lastAccessTime; }
 254      set {
 255        if (!IsValidValue(value)) {
 256          throw new ArgumentOutOfRangeException(nameof(value));
 257        }
 258
 259        _flags |= Flags.AccessTime;
 260        _lastAccessTime = value;
 261      }
 262    }
 263
 264    /// <summary>
 265    /// Get / Set the Create Time
 266    /// </summary>
 267    /// <exception cref="ArgumentOutOfRangeException"></exception>
 268    /// <seealso cref="IsValidValue"></seealso>
 269    public DateTime CreateTime {
 270      get { return _createTime; }
 271      set {
 272        if (!IsValidValue(value)) {
 273          throw new ArgumentOutOfRangeException(nameof(value));
 274        }
 275
 276        _flags |= Flags.CreateTime;
 277        _createTime = value;
 278      }
 279    }
 280
 281    /// <summary>
 282    /// Get/set the <see cref="Flags">values</see> to include.
 283    /// </summary>
 284    public Flags Include
 285    {
 286      get { return _flags; }
 287      set { _flags = value; }
 288    }
 289
 290    #region Instance Fields
 291    Flags _flags;
 292    DateTime _modificationTime = new DateTime(1970, 1, 1);
 293    DateTime _lastAccessTime = new DateTime(1970, 1, 1);
 294    DateTime _createTime = new DateTime(1970, 1, 1);
 295    #endregion
 296  }
 297
 298  /// <summary>
 299  /// Class handling NT date time values.
 300  /// </summary>
 301  public class NTTaggedData : ITaggedData
 302  {
 303    /// <summary>
 304    /// Get the ID for this tagged data value.
 305    /// </summary>
 306    public short TagID {
 307      get { return 10; }
 308    }
 309
 310    /// <summary>
 311    /// Set the data from the raw values provided.
 312    /// </summary>
 313    /// <param name="data">The raw data to extract values from.</param>
 314    /// <param name="index">The index to start extracting values from.</param>
 315    /// <param name="count">The number of bytes available.</param>
 316    public void SetData(byte[] data, int index, int count)
 317    {
 318      using (MemoryStream ms = new MemoryStream(data, index, count, false))
 319      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 320        helperStream.ReadLEInt(); // Reserved
 321        while (helperStream.Position < helperStream.Length) {
 322          int ntfsTag = helperStream.ReadLEShort();
 323          int ntfsLength = helperStream.ReadLEShort();
 324          if (ntfsTag == 1) {
 325            if (ntfsLength >= 24) {
 326              long lastModificationTicks = helperStream.ReadLELong();
 327              _lastModificationTime = DateTime.FromFileTimeUtc(lastModificationTicks);
 328
 329              long lastAccessTicks = helperStream.ReadLELong();
 330              _lastAccessTime = DateTime.FromFileTimeUtc(lastAccessTicks);
 331
 332              long createTimeTicks = helperStream.ReadLELong();
 333              _createTime = DateTime.FromFileTimeUtc(createTimeTicks);
 334            }
 335            break;
 336          } else {
 337            // An unknown NTFS tag so simply skip it.
 338            helperStream.Seek(ntfsLength, SeekOrigin.Current);
 339          }
 340        }
 341      }
 342    }
 343
 344    /// <summary>
 345    /// Get the binary data representing this instance.
 346    /// </summary>
 347    /// <returns>The raw binary data representing this instance.</returns>
 348    public byte[] GetData()
 349    {
 350      using (MemoryStream ms = new MemoryStream())
 351      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {
 352        helperStream.IsStreamOwner = false;
 353        helperStream.WriteLEInt(0);       // Reserved
 354        helperStream.WriteLEShort(1);     // Tag
 355        helperStream.WriteLEShort(24);    // Length = 3 x 8.
 356        helperStream.WriteLELong(_lastModificationTime.ToFileTimeUtc());
 357        helperStream.WriteLELong(_lastAccessTime.ToFileTimeUtc());
 358        helperStream.WriteLELong(_createTime.ToFileTimeUtc());
 359        return ms.ToArray();
 360      }
 361    }
 362
 363    /// <summary>
 364    /// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>
 365    /// </summary>
 366    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 367    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 368    /// <remarks>
 369    /// NTFS filetimes are 64-bit unsigned integers, stored in Intel
 370    /// (least significant byte first) byte order. They determine the
 371    /// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
 372    /// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit
 373    /// </remarks>
 374    public static bool IsValidValue(DateTime value)
 375    {
 376      bool result = true;
 377      try {
 378        value.ToFileTimeUtc();
 379      } catch {
 380        result = false;
 381      }
 382      return result;
 383    }
 384
 385    /// <summary>
 386    /// Get/set the <see cref="DateTime">last modification time</see>.
 387    /// </summary>
 388    public DateTime LastModificationTime {
 389      get { return _lastModificationTime; }
 390      set {
 391        if (!IsValidValue(value)) {
 392          throw new ArgumentOutOfRangeException(nameof(value));
 393        }
 394        _lastModificationTime = value;
 395      }
 396    }
 397
 398    /// <summary>
 399    /// Get /set the <see cref="DateTime">create time</see>
 400    /// </summary>
 401    public DateTime CreateTime {
 402      get { return _createTime; }
 403      set {
 404        if (!IsValidValue(value)) {
 405          throw new ArgumentOutOfRangeException(nameof(value));
 406        }
 407        _createTime = value;
 408      }
 409    }
 410
 411    /// <summary>
 412    /// Get /set the <see cref="DateTime">last access time</see>.
 413    /// </summary>
 414    public DateTime LastAccessTime {
 415      get { return _lastAccessTime; }
 416      set {
 417        if (!IsValidValue(value)) {
 418          throw new ArgumentOutOfRangeException(nameof(value));
 419        }
 420        _lastAccessTime = value;
 421      }
 422    }
 423
 424    #region Instance Fields
 425    DateTime _lastAccessTime = DateTime.FromFileTimeUtc(0);
 426    DateTime _lastModificationTime = DateTime.FromFileTimeUtc(0);
 427    DateTime _createTime = DateTime.FromFileTimeUtc(0);
 428    #endregion
 429  }
 430
 431  /// <summary>
 432  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.
 433  /// </summary>
 434  interface ITaggedDataFactory
 435  {
 436    /// <summary>
 437    /// Get data for a specific tag value.
 438    /// </summary>
 439    /// <param name="tag">The tag ID to find.</param>
 440    /// <param name="data">The data to search.</param>
 441    /// <param name="offset">The offset to begin extracting data from.</param>
 442    /// <param name="count">The number of bytes to extract.</param>
 443    /// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>
 444    ITaggedData Create(short tag, byte[] data, int offset, int count);
 445  }
 446
 447  ///
 448  /// <summary>
 449  /// A class to handle the extra data field for Zip entries
 450  /// </summary>
 451  /// <remarks>
 452  /// Extra data contains 0 or more values each prefixed by a header tag and length.
 453  /// They contain zero or more bytes of actual data.
 454  /// The data is held internally using a copy on write strategy.  This is more efficient but
 455  /// means that for extra data created by passing in data can have the values modified by the caller
 456  /// in some circumstances.
 457  /// </remarks>
 458  sealed public class ZipExtraData : IDisposable
 459  {
 460    #region Constructors
 461    /// <summary>
 462    /// Initialise a default instance.
 463    /// </summary>
 5464    public ZipExtraData()
 465    {
 5466      Clear();
 5467    }
 468
 469    /// <summary>
 470    /// Initialise with known extra data.
 471    /// </summary>
 472    /// <param name="data">The extra data.</param>
 329692473    public ZipExtraData(byte[] data)
 474    {
 329692475       if (data == null) {
 131944476        _data = new byte[0];
 131944477      } else {
 197748478        _data = data;
 479      }
 197748480    }
 481    #endregion
 482
 483    /// <summary>
 484    /// Get the raw extra data value
 485    /// </summary>
 486    /// <returns>Returns the raw byte[] extra data this instance represents.</returns>
 487    public byte[] GetEntryData()
 488    {
 131788489       if (Length > ushort.MaxValue) {
 0490        throw new ZipException("Data exceeds maximum length");
 491      }
 492
 131788493      return (byte[])_data.Clone();
 494    }
 495
 496    /// <summary>
 497    /// Clear the stored data.
 498    /// </summary>
 499    public void Clear()
 500    {
 5501       if ((_data == null) || (_data.Length != 0)) {
 5502        _data = new byte[0];
 503      }
 5504    }
 505
 506    /// <summary>
 507    /// Gets the current extra data length.
 508    /// </summary>
 509    public int Length {
 131811510      get { return _data.Length; }
 511    }
 512
 513    /// <summary>
 514    /// Get a read-only <see cref="Stream"/> for the associated tag.
 515    /// </summary>
 516    /// <param name="tag">The tag to locate data for.</param>
 517    /// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>
 518    public Stream GetStreamForTag(int tag)
 519    {
 4520      Stream result = null;
 4521       if (Find(tag)) {
 4522        result = new MemoryStream(_data, _index, _readValueLength, false);
 523      }
 4524      return result;
 525    }
 526
 527    /// <summary>
 528    /// Get the <see cref="ITaggedData">tagged data</see> for a tag.
 529    /// </summary>
 530    /// <typeparam name="T">The tag to search for.</typeparam>
 531    /// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>
 532    public T GetData<T>()
 533      where T : class, ITaggedData, new()
 534    {
 66037535      T result = new T();
 66037536       if (Find(result.TagID))
 537      {
 0538        result.SetData(_data, _readValueStart, _readValueLength);
 0539        return result;
 540      }
 66037541      else return null;
 542    }
 543
 544    /// <summary>
 545    /// Get the length of the last value found by <see cref="Find"/>
 546    /// </summary>
 547    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.</remarks>
 548    public int ValueLength {
 146549      get { return _readValueLength; }
 550    }
 551
 552    /// <summary>
 553    /// Get the index for the current read value.
 554    /// </summary>
 555    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.
 556    /// Initially the result will be the index of the first byte of actual data.  The value is updated after calls to
 557    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>
 558    public int CurrentReadIndex {
 101559      get { return _index; }
 560    }
 561
 562    /// <summary>
 563    /// Get the number of bytes remaining to be read for the current value;
 564    /// </summary>
 565    public int UnreadCount {
 566      get {
 16567         if ((_readValueStart > _data.Length) ||
 16568          (_readValueStart < 4)) {
 0569          throw new ZipException("Find must be called before calling a Read method");
 570        }
 571
 16572        return _readValueStart + _readValueLength - _index;
 573      }
 574    }
 575
 576    /// <summary>
 577    /// Find an extra data value
 578    /// </summary>
 579    /// <param name="headerID">The identifier for the value to find.</param>
 580    /// <returns>Returns true if the value was found; false otherwise.</returns>
 581    public bool Find(int headerID)
 582    {
 396136583      _readValueStart = _data.Length;
 396136584      _readValueLength = 0;
 396136585      _index = 0;
 586
 396136587      int localLength = _readValueStart;
 396136588      int localTag = headerID - 1;
 589
 590      // Trailing bytes that cant make up an entry (as there arent enough
 591      // bytes for a tag and length) are ignored!
 396614592       while ((localTag != headerID) && (_index < _data.Length - 3)) {
 478593        localTag = ReadShortInternal();
 478594        localLength = ReadShortInternal();
 478595         if (localTag != headerID) {
 148596          _index += localLength;
 597        }
 598      }
 599
 396136600      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);
 601
 396136602       if (result) {
 330603        _readValueStart = _index;
 330604        _readValueLength = localLength;
 605      }
 606
 396136607      return result;
 608    }
 609
 610    /// <summary>
 611    /// Add a new entry to extra data.
 612    /// </summary>
 613    /// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>
 614    public void AddEntry(ITaggedData taggedData)
 615    {
 0616       if (taggedData == null) {
 0617        throw new ArgumentNullException(nameof(taggedData));
 618      }
 0619      AddEntry(taggedData.TagID, taggedData.GetData());
 0620    }
 621
 622    /// <summary>
 623    /// Add a new entry to extra data
 624    /// </summary>
 625    /// <param name="headerID">The ID for this entry.</param>
 626    /// <param name="fieldData">The data to add.</param>
 627    /// <remarks>If the ID already exists its contents are replaced.</remarks>
 628    public void AddEntry(int headerID, byte[] fieldData)
 629    {
 261630       if ((headerID > ushort.MaxValue) || (headerID < 0)) {
 0631        throw new ArgumentOutOfRangeException(nameof(headerID));
 632      }
 633
 261634      int addLength = (fieldData == null) ? 0 : fieldData.Length;
 635
 261636       if (addLength > ushort.MaxValue) {
 0637        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");
 638      }
 639
 640      // Test for new length before adjusting data.
 261641      int newLength = _data.Length + addLength + 4;
 642
 261643       if (Find(headerID)) {
 4644        newLength -= (ValueLength + 4);
 645      }
 646
 261647       if (newLength > ushort.MaxValue) {
 2648        throw new ZipException("Data exceeds maximum length");
 649      }
 650
 259651      Delete(headerID);
 652
 259653      byte[] newData = new byte[newLength];
 259654      _data.CopyTo(newData, 0);
 259655      int index = _data.Length;
 259656      _data = newData;
 259657      SetShort(ref index, headerID);
 259658      SetShort(ref index, addLength);
 259659       if (fieldData != null) {
 257660        fieldData.CopyTo(newData, index);
 661      }
 259662    }
 663
 664    /// <summary>
 665    /// Start adding a new entry.
 666    /// </summary>
 667    /// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see
 668    /// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>
 669    /// <seealso cref="AddEntry(ITaggedData)"/>
 670    public void StartNewEntry()
 671    {
 249672      _newEntry = new MemoryStream();
 249673    }
 674
 675    /// <summary>
 676    /// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.
 677    /// </summary>
 678    /// <param name="headerID">The identifier to use for this entry.</param>
 679    public void AddNewEntry(int headerID)
 680    {
 249681      byte[] newData = _newEntry.ToArray();
 249682      _newEntry = null;
 249683      AddEntry(headerID, newData);
 249684    }
 685
 686    /// <summary>
 687    /// Add a byte of data to the pending new entry.
 688    /// </summary>
 689    /// <param name="data">The byte to add.</param>
 690    /// <seealso cref="StartNewEntry"/>
 691    public void AddData(byte data)
 692    {
 1693      _newEntry.WriteByte(data);
 1694    }
 695
 696    /// <summary>
 697    /// Add data to a pending new entry.
 698    /// </summary>
 699    /// <param name="data">The data to add.</param>
 700    /// <seealso cref="StartNewEntry"/>
 701    public void AddData(byte[] data)
 702    {
 0703       if (data == null) {
 0704        throw new ArgumentNullException(nameof(data));
 705      }
 706
 0707      _newEntry.Write(data, 0, data.Length);
 0708    }
 709
 710    /// <summary>
 711    /// Add a short value in little endian order to the pending new entry.
 712    /// </summary>
 713    /// <param name="toAdd">The data to add.</param>
 714    /// <seealso cref="StartNewEntry"/>
 715    public void AddLeShort(int toAdd)
 716    {
 717      unchecked {
 2004718        _newEntry.WriteByte((byte)toAdd);
 2004719        _newEntry.WriteByte((byte)(toAdd >> 8));
 720      }
 2004721    }
 722
 723    /// <summary>
 724    /// Add an integer value in little endian order to the pending new entry.
 725    /// </summary>
 726    /// <param name="toAdd">The data to add.</param>
 727    /// <seealso cref="StartNewEntry"/>
 728    public void AddLeInt(int toAdd)
 729    {
 730      unchecked {
 1002731        AddLeShort((short)toAdd);
 1002732        AddLeShort((short)(toAdd >> 16));
 733      }
 1002734    }
 735
 736    /// <summary>
 737    /// Add a long value in little endian order to the pending new entry.
 738    /// </summary>
 739    /// <param name="toAdd">The data to add.</param>
 740    /// <seealso cref="StartNewEntry"/>
 741    public void AddLeLong(long toAdd)
 742    {
 743      unchecked {
 501744        AddLeInt((int)(toAdd & 0xffffffff));
 501745        AddLeInt((int)(toAdd >> 32));
 746      }
 501747    }
 748
 749    /// <summary>
 750    /// Delete an extra data field.
 751    /// </summary>
 752    /// <param name="headerID">The identifier of the field to delete.</param>
 753    /// <returns>Returns true if the field was found and deleted.</returns>
 754    public bool Delete(int headerID)
 755    {
 131791756      bool result = false;
 757
 131791758       if (Find(headerID)) {
 6759        result = true;
 6760        int trueStart = _readValueStart - 4;
 761
 6762        byte[] newData = new byte[_data.Length - (ValueLength + 4)];
 6763        Array.Copy(_data, 0, newData, 0, trueStart);
 764
 6765        int trueEnd = trueStart + ValueLength + 4;
 6766        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);
 6767        _data = newData;
 768      }
 131791769      return result;
 770    }
 771
 772    #region Reading Support
 773    /// <summary>
 774    /// Read a long in little endian form from the last <see cref="Find">found</see> data value
 775    /// </summary>
 776    /// <returns>Returns the long value read.</returns>
 777    public long ReadLong()
 778    {
 357779      ReadCheck(8);
 354780      return (ReadInt() & 0xffffffff) | (((long)ReadInt()) << 32);
 781    }
 782
 783    /// <summary>
 784    /// Read an integer in little endian form from the last <see cref="Find">found</see> data value.
 785    /// </summary>
 786    /// <returns>Returns the integer read.</returns>
 787    public int ReadInt()
 788    {
 712789      ReadCheck(4);
 790
 709791      int result = _data[_index] + (_data[_index + 1] << 8) +
 709792        (_data[_index + 2] << 16) + (_data[_index + 3] << 24);
 709793      _index += 4;
 709794      return result;
 795    }
 796
 797    /// <summary>
 798    /// Read a short value in little endian form from the last <see cref="Find">found</see> data value.
 799    /// </summary>
 800    /// <returns>Returns the short value read.</returns>
 801    public int ReadShort()
 802    {
 4803      ReadCheck(2);
 1804      int result = _data[_index] + (_data[_index + 1] << 8);
 1805      _index += 2;
 1806      return result;
 807    }
 808
 809    /// <summary>
 810    /// Read a byte from an extra data
 811    /// </summary>
 812    /// <returns>The byte value read or -1 if the end of data has been reached.</returns>
 813    public int ReadByte()
 814    {
 26815      int result = -1;
 26816       if ((_index < _data.Length) && (_readValueStart + _readValueLength > _index)) {
 19817        result = _data[_index];
 19818        _index += 1;
 819      }
 26820      return result;
 821    }
 822
 823    /// <summary>
 824    /// Skip data during reading.
 825    /// </summary>
 826    /// <param name="amount">The number of bytes to skip.</param>
 827    public void Skip(int amount)
 828    {
 6829      ReadCheck(amount);
 4830      _index += amount;
 4831    }
 832
 833    void ReadCheck(int length)
 834    {
 1079835       if ((_readValueStart > _data.Length) ||
 1079836        (_readValueStart < 4)) {
 0837        throw new ZipException("Find must be called before calling a Read method");
 838      }
 839
 1079840       if (_index > _readValueStart + _readValueLength - length) {
 10841        throw new ZipException("End of extra data");
 842      }
 843
 1069844       if (_index + length < 4) {
 1845        throw new ZipException("Cannot read before start of tag");
 846      }
 1068847    }
 848
 849    /// <summary>
 850    /// Internal form of <see cref="ReadShort"/> that reads data at any location.
 851    /// </summary>
 852    /// <returns>Returns the short value read.</returns>
 853    int ReadShortInternal()
 854    {
 956855       if (_index > _data.Length - 2) {
 0856        throw new ZipException("End of extra data");
 857      }
 858
 956859      int result = _data[_index] + (_data[_index + 1] << 8);
 956860      _index += 2;
 956861      return result;
 862    }
 863
 864    void SetShort(ref int index, int source)
 865    {
 518866      _data[index] = (byte)source;
 518867      _data[index + 1] = (byte)(source >> 8);
 518868      index += 2;
 518869    }
 870
 871    #endregion
 872
 873    #region IDisposable Members
 874
 875    /// <summary>
 876    /// Dispose of this instance.
 877    /// </summary>
 878    public void Dispose()
 879    {
 0880       if (_newEntry != null) {
 0881        _newEntry.Close();
 882      }
 0883    }
 884
 885    #endregion
 886
 887    #region Instance Fields
 888    int _index;
 889    int _readValueStart;
 890    int _readValueLength;
 891
 892    MemoryStream _newEntry;
 893    byte[] _data;
 894    #endregion
 895  }
 896}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipFile.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipFile.htm new file mode 100644 index 000000000..cba4fbe77 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipFile.htm @@ -0,0 +1,4415 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipFile - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipFile
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs
Covered lines:953
Uncovered lines:356
Coverable lines:1309
Total lines:4263
Line coverage:72.8%
Branch coverage:58.6%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
OnKeysRequired(...)24066.67
.ctor(...)293.3366.67
.ctor(...)335.2940
.ctor(...)473.6871.43
.ctor()1100100
Finalize()1100100
Close()1100100
Create(...)287.566.67
Create(...)466.6757.14
GetEnumerator()266.6766.67
FindEntry(...)487.585.71
GetEntry(...)300
GetInputStream(...)75046.15
GetInputStream(...)678.5772.73
TestArchive(...)1100100
TestArchive(...)2553.6260
TestLocalHeader(...)7465.9655.24
BeginUpdate(...)987.1063.64
BeginUpdate(...)1100100
BeginUpdate()2100100
CommitUpdate()79077.78
AbortUpdate()100
SetComment(...)366.6760
AddUpdate(...)363.6440
Add(...)400
Add(...)300
Add(...)28066.67
Add(...)300
Add(...)371.4360
Add(...)377.7860
Add(...)38060
Add(...)471.4357.14
AddDirectory(...)200
Delete(...)484.6257.14
Delete(...)38060
WriteLEShort(...)1100100
WriteLEUshort(...)1100100
WriteLEInt(...)1100100
WriteLEUint(...)1100100
WriteLeLong(...)1100100
WriteLEUlong(...)100
WriteLocalEntryHeader(...)2093.6582.05
WriteCentralDirectoryHeader(...)2483.6166.67
PostUpdateCleanup()2100100
GetTransformedFileName(...)210066.67
GetTransformedDirectoryName(...)200
GetBuffer()2100100
CopyDescriptorBytes(...)42528.57
CopyBytes(...)990.9164.71
GetDescriptorSize(...)35040
CopyDescriptorBytesDirect(...)32040
CopyEntryDataDirect(...)88853.33
FindExistingUpdate(...)210066.67
FindExistingUpdate(...)2100100
GetOutputStream(...)491.6785.71
AddEntry(...)996.3084.62
ModifyEntry(...)500
CopyEntryDirect(...)510088.89
CopyEntry(...)210066.67
Reopen(...)283.3366.67
Reopen()200
UpdateCommentOnly()687.1077.78
RunUpdates()2991.1484.62
CheckUpdating()266.6766.67
System.IDisposable.Dispose()1100100
DisposeInternal(...)5100100
Dispose(...)1100100
ReadLEUshort()371.4360
ReadLEUint()1100100
ReadLEUlong()1100100
LocateBlockWithSignature(...)2100100
ReadEntries()2092.3974.36
LocateEntry(...)1100100
CreateAndInitDecryptionStream(...)931.0323.53
CreateAndInitEncryptionStream(...)683.3354.55
CheckClassicPassword(...)28066.67
WriteEncryptionHeader(...)1100100
Compare(...)1310088.24
.ctor(...)1100100
.ctor(...)100
.ctor(...)100
.ctor(...)100
.ctor(...)1100100
.ctor(...)100
.ctor(...)1100100
.ctor(...)1100100
GetSource()2100100
.ctor(...)1100100
.ctor(...)100
Reset()200
MakeTextAvailable()200
MakeBytesAvailable()2100100
op_Implicit(...)100
.ctor(...)1100100
Reset()100
MoveNext()1100100
.ctor(...)1100100
Close()1100100
Flush()100
Read(...)100
Seek(...)100
SetLength(...)100
Write(...)1100100
.ctor(...)1100100
ReadByte()383.3366.67
Close()1100100
Read(...)691.6777.78
Write(...)100
SetLength(...)100
Seek(...)661.5444.44
Flush()100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipFile.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.IO;
 4using System.Text;
 5using System.Globalization;
 6using System.Security.Cryptography;
 7using ICSharpCode.SharpZipLib.Encryption;
 8using ICSharpCode.SharpZipLib.Core;
 9using ICSharpCode.SharpZipLib.Checksum;
 10using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 11using ICSharpCode.SharpZipLib.Zip.Compression;
 12
 13namespace ICSharpCode.SharpZipLib.Zip
 14{
 15  #region Keys Required Event Args
 16  /// <summary>
 17  /// Arguments used with KeysRequiredEvent
 18  /// </summary>
 19  public class KeysRequiredEventArgs : EventArgs
 20  {
 21    #region Constructors
 22    /// <summary>
 23    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 24    /// </summary>
 25    /// <param name="name">The name of the file for which keys are required.</param>
 26    public KeysRequiredEventArgs(string name)
 27    {
 28      fileName = name;
 29    }
 30
 31    /// <summary>
 32    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
 33    /// </summary>
 34    /// <param name="name">The name of the file for which keys are required.</param>
 35    /// <param name="keyValue">The current key value.</param>
 36    public KeysRequiredEventArgs(string name, byte[] keyValue)
 37    {
 38      fileName = name;
 39      key = keyValue;
 40    }
 41
 42    #endregion
 43    #region Properties
 44    /// <summary>
 45    /// Gets the name of the file for which keys are required.
 46    /// </summary>
 47    public string FileName {
 48      get { return fileName; }
 49    }
 50
 51    /// <summary>
 52    /// Gets or sets the key value
 53    /// </summary>
 54    public byte[] Key {
 55      get { return key; }
 56      set { key = value; }
 57    }
 58    #endregion
 59
 60    #region Instance Fields
 61    string fileName;
 62    byte[] key;
 63    #endregion
 64  }
 65  #endregion
 66
 67  #region Test Definitions
 68  /// <summary>
 69  /// The strategy to apply to testing.
 70  /// </summary>
 71  public enum TestStrategy
 72  {
 73    /// <summary>
 74    /// Find the first error only.
 75    /// </summary>
 76    FindFirstError,
 77    /// <summary>
 78    /// Find all possible errors.
 79    /// </summary>
 80    FindAllErrors,
 81  }
 82
 83  /// <summary>
 84  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.
 85  /// </summary>
 86  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 87  public enum TestOperation
 88  {
 89    /// <summary>
 90    /// Setting up testing.
 91    /// </summary>
 92    Initialising,
 93
 94    /// <summary>
 95    /// Testing an individual entries header
 96    /// </summary>
 97    EntryHeader,
 98
 99    /// <summary>
 100    /// Testing an individual entries data
 101    /// </summary>
 102    EntryData,
 103
 104    /// <summary>
 105    /// Testing an individual entry has completed.
 106    /// </summary>
 107    EntryComplete,
 108
 109    /// <summary>
 110    /// Running miscellaneous tests
 111    /// </summary>
 112    MiscellaneousTests,
 113
 114    /// <summary>
 115    /// Testing is complete
 116    /// </summary>
 117    Complete,
 118  }
 119
 120  /// <summary>
 121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.
 122  /// </summary>
 123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
 124  public class TestStatus
 125  {
 126    #region Constructors
 127    /// <summary>
 128    /// Initialise a new instance of <see cref="TestStatus"/>
 129    /// </summary>
 130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>
 131    public TestStatus(ZipFile file)
 132    {
 133      file_ = file;
 134    }
 135    #endregion
 136
 137    #region Properties
 138
 139    /// <summary>
 140    /// Get the current <see cref="TestOperation"/> in progress.
 141    /// </summary>
 142    public TestOperation Operation {
 143      get { return operation_; }
 144    }
 145
 146    /// <summary>
 147    /// Get the <see cref="ZipFile"/> this status is applicable to.
 148    /// </summary>
 149    public ZipFile File {
 150      get { return file_; }
 151    }
 152
 153    /// <summary>
 154    /// Get the current/last entry tested.
 155    /// </summary>
 156    public ZipEntry Entry {
 157      get { return entry_; }
 158    }
 159
 160    /// <summary>
 161    /// Get the number of errors detected so far.
 162    /// </summary>
 163    public int ErrorCount {
 164      get { return errorCount_; }
 165    }
 166
 167    /// <summary>
 168    /// Get the number of bytes tested so far for the current entry.
 169    /// </summary>
 170    public long BytesTested {
 171      get { return bytesTested_; }
 172    }
 173
 174    /// <summary>
 175    /// Get a value indicating wether the last entry test was valid.
 176    /// </summary>
 177    public bool EntryValid {
 178      get { return entryValid_; }
 179    }
 180    #endregion
 181
 182    #region Internal API
 183    internal void AddError()
 184    {
 185      errorCount_++;
 186      entryValid_ = false;
 187    }
 188
 189    internal void SetOperation(TestOperation operation)
 190    {
 191      operation_ = operation;
 192    }
 193
 194    internal void SetEntry(ZipEntry entry)
 195    {
 196      entry_ = entry;
 197      entryValid_ = true;
 198      bytesTested_ = 0;
 199    }
 200
 201    internal void SetBytesTested(long value)
 202    {
 203      bytesTested_ = value;
 204    }
 205    #endregion
 206
 207    #region Instance Fields
 208    ZipFile file_;
 209    ZipEntry entry_;
 210    bool entryValid_;
 211    int errorCount_;
 212    long bytesTested_;
 213    TestOperation operation_;
 214    #endregion
 215  }
 216
 217  /// <summary>
 218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if
 219  /// </summary>
 220  /// <remarks>If the message is non-null an error has occured.  If the message is null
 221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>
 222  public delegate void ZipTestResultHandler(TestStatus status, string message);
 223  #endregion
 224
 225  #region Update Definitions
 226  /// <summary>
 227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.
 228  /// </summary>
 229  public enum FileUpdateMode
 230  {
 231    /// <summary>
 232    /// Perform all updates on temporary files ensuring that the original file is saved.
 233    /// </summary>
 234    Safe,
 235    /// <summary>
 236    /// Update the archive directly, which is faster but less safe.
 237    /// </summary>
 238    Direct,
 239  }
 240  #endregion
 241
 242  #region ZipFile Class
 243  /// <summary>
 244  /// This class represents a Zip archive.  You can ask for the contained
 245  /// entries, or get an input stream for a file entry.  The entry is
 246  /// automatically decompressed.
 247  ///
 248  /// You can also update the archive adding or deleting entries.
 249  ///
 250  /// This class is thread safe for input:  You can open input streams for arbitrary
 251  /// entries in different threads.
 252  /// <br/>
 253  /// <br/>Author of the original java version : Jochen Hoenicke
 254  /// </summary>
 255  /// <example>
 256  /// <code>
 257  /// using System;
 258  /// using System.Text;
 259  /// using System.Collections;
 260  /// using System.IO;
 261  ///
 262  /// using ICSharpCode.SharpZipLib.Zip;
 263  ///
 264  /// class MainClass
 265  /// {
 266  ///   static public void Main(string[] args)
 267  ///   {
 268  ///     using (ZipFile zFile = new ZipFile(args[0])) {
 269  ///       Console.WriteLine("Listing of : " + zFile.Name);
 270  ///       Console.WriteLine("");
 271  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");
 272  ///       Console.WriteLine("--------  --------  --------  ------  ---------");
 273  ///       foreach (ZipEntry e in zFile) {
 274  ///         if ( e.IsFile ) {
 275  ///           DateTime d = e.DateTime;
 276  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,
 277  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),
 278  ///             e.Name);
 279  ///         }
 280  ///       }
 281  ///     }
 282  ///   }
 283  /// }
 284  /// </code>
 285  /// </example>
 286  public class ZipFile : IEnumerable, IDisposable
 287  {
 288    #region KeyHandling
 289
 290    /// <summary>
 291    /// Delegate for handling keys/password setting during compresion/decompression.
 292    /// </summary>
 293    public delegate void KeysRequiredEventHandler(
 294      object sender,
 295      KeysRequiredEventArgs e
 296    );
 297
 298    /// <summary>
 299    /// Event handler for handling encryption keys.
 300    /// </summary>
 301    public KeysRequiredEventHandler KeysRequired;
 302
 303    /// <summary>
 304    /// Handles getting of encryption keys when required.
 305    /// </summary>
 306    /// <param name="fileName">The file for which encryption keys are required.</param>
 307    void OnKeysRequired(string fileName)
 308    {
 15309       if (KeysRequired != null) {
 0310        var krea = new KeysRequiredEventArgs(fileName, key);
 0311        KeysRequired(this, krea);
 0312        key = krea.Key;
 313      }
 15314    }
 315
 316    /// <summary>
 317    /// Get/set the encryption key value.
 318    /// </summary>
 319    byte[] Key {
 0320      get { return key; }
 0321      set { key = value; }
 322    }
 323
 324    /// <summary>
 325    /// Password to be used for encrypting/decrypting files.
 326    /// </summary>
 327    /// <remarks>Set to null if no password is required.</remarks>
 328    public string Password {
 329      set {
 16330         if (string.IsNullOrEmpty(value)) {
 5331          key = null;
 5332        } else {
 11333          rawPassword_ = value;
 11334          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));
 335        }
 11336      }
 337    }
 338
 339    /// <summary>
 340    /// Get a value indicating wether encryption keys are currently available.
 341    /// </summary>
 342    bool HaveKeys {
 65720343      get { return key != null; }
 344    }
 345    #endregion
 346
 347    #region Constructors
 348    /// <summary>
 349    /// Opens a Zip file with the given name for reading.
 350    /// </summary>
 351    /// <param name="name">The name of the file to open.</param>
 352    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>
 353    /// <exception cref="IOException">
 354    /// An i/o error occurs
 355    /// </exception>
 356    /// <exception cref="ZipException">
 357    /// The file doesn't contain a valid zip archive.
 358    /// </exception>
 15359    public ZipFile(string name)
 360    {
 15361       if (name == null) {
 0362        throw new ArgumentNullException(nameof(name));
 363      }
 364
 15365      name_ = name;
 366
 15367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 15368      isStreamOwner = true;
 369
 370      try {
 15371        ReadEntries();
 15372      } catch {
 1373        DisposeInternal(true);
 1374        throw;
 375      }
 14376    }
 377
 378    /// <summary>
 379    /// Opens a Zip file reading the given <see cref="FileStream"/>.
 380    /// </summary>
 381    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>
 382    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>
 383    /// <exception cref="IOException">
 384    /// An i/o error occurs.
 385    /// </exception>
 386    /// <exception cref="ZipException">
 387    /// The file doesn't contain a valid zip archive.
 388    /// </exception>
 1389    public ZipFile(FileStream file)
 390    {
 1391       if (file == null) {
 1392        throw new ArgumentNullException(nameof(file));
 393      }
 394
 0395       if (!file.CanSeek) {
 0396        throw new ArgumentException("Stream is not seekable", nameof(file));
 397      }
 398
 0399      baseStream_ = file;
 0400      name_ = file.Name;
 0401      isStreamOwner = true;
 402
 403      try {
 0404        ReadEntries();
 0405      } catch {
 0406        DisposeInternal(true);
 0407        throw;
 408      }
 0409    }
 410
 411    /// <summary>
 412    /// Opens a Zip file reading the given <see cref="Stream"/>.
 413    /// </summary>
 414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
 415    /// <exception cref="IOException">
 416    /// An i/o error occurs
 417    /// </exception>
 418    /// <exception cref="ZipException">
 419    /// The stream doesn't contain a valid zip archive.<br/>
 420    /// </exception>
 421    /// <exception cref="ArgumentException">
 422    /// The <see cref="Stream">stream</see> doesnt support seeking.
 423    /// </exception>
 424    /// <exception cref="ArgumentNullException">
 425    /// The <see cref="Stream">stream</see> argument is null.
 426    /// </exception>
 62427    public ZipFile(Stream stream)
 428    {
 62429       if (stream == null) {
 0430        throw new ArgumentNullException(nameof(stream));
 431      }
 432
 62433       if (!stream.CanSeek) {
 0434        throw new ArgumentException("Stream is not seekable", nameof(stream));
 435      }
 436
 62437      baseStream_ = stream;
 62438      isStreamOwner = true;
 439
 62440       if (baseStream_.Length > 0) {
 441        try {
 52442          ReadEntries();
 52443        } catch {
 0444          DisposeInternal(true);
 0445          throw;
 446        }
 447      } else {
 10448        entries_ = new ZipEntry[0];
 10449        isNewArchive_ = true;
 450      }
 62451    }
 452
 453    /// <summary>
 454    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
 455    /// </summary>
 10456    internal ZipFile()
 457    {
 10458      entries_ = new ZipEntry[0];
 10459      isNewArchive_ = true;
 10460    }
 461
 462    #endregion
 463
 464    #region Destructors and Closing
 465    /// <summary>
 466    /// Finalize this instance.
 467    /// </summary>
 468    ~ZipFile()
 469    {
 6470      Dispose(false);
 12471    }
 472
 473    /// <summary>
 474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying
 475    /// Once closed, no further instance methods should be called.
 476    /// </summary>
 477    /// <exception cref="System.IO.IOException">
 478    /// An i/o error occurs.
 479    /// </exception>
 480    public void Close()
 481    {
 91482      DisposeInternal(true);
 91483      GC.SuppressFinalize(this);
 91484    }
 485
 486    #endregion
 487
 488    #region Creators
 489    /// <summary>
 490    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.
 491    /// </summary>
 492    /// <param name="fileName">The name of the archive to create.</param>
 493    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 494    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>
 495    public static ZipFile Create(string fileName)
 496    {
 7497       if (fileName == null) {
 0498        throw new ArgumentNullException(nameof(fileName));
 499      }
 500
 7501      FileStream fs = File.Create(fileName);
 502
 7503      var result = new ZipFile();
 7504      result.name_ = fileName;
 7505      result.baseStream_ = fs;
 7506      result.isStreamOwner = true;
 7507      return result;
 508    }
 509
 510    /// <summary>
 511    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.
 512    /// </summary>
 513    /// <param name="outStream">The stream providing data storage.</param>
 514    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
 515    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>
 516    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>
 517    public static ZipFile Create(Stream outStream)
 518    {
 3519       if (outStream == null) {
 0520        throw new ArgumentNullException(nameof(outStream));
 521      }
 522
 3523       if (!outStream.CanWrite) {
 0524        throw new ArgumentException("Stream is not writeable", nameof(outStream));
 525      }
 526
 3527       if (!outStream.CanSeek) {
 0528        throw new ArgumentException("Stream is not seekable", nameof(outStream));
 529      }
 530
 3531      var result = new ZipFile();
 3532      result.baseStream_ = outStream;
 3533      return result;
 534    }
 535
 536    #endregion
 537
 538    #region Properties
 539    /// <summary>
 540    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
 541    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
 542    /// </summary>
 543    /// <remarks>
 544    /// The default value is true in all cases.
 545    /// </remarks>
 546    public bool IsStreamOwner {
 88547      get { return isStreamOwner; }
 74548      set { isStreamOwner = value; }
 549    }
 550
 551    /// <summary>
 552    /// Get a value indicating wether
 553    /// this archive is embedded in another file or not.
 554    /// </summary>
 555    public bool IsEmbeddedArchive {
 556      // Not strictly correct in all circumstances currently
 48557      get { return offsetOfFirstEntry > 0; }
 558    }
 559
 560    /// <summary>
 561    /// Get a value indicating that this archive is a new one.
 562    /// </summary>
 563    public bool IsNewArchive {
 65793564      get { return isNewArchive_; }
 565    }
 566
 567    /// <summary>
 568    /// Gets the comment for the zip file.
 569    /// </summary>
 570    public string ZipFileComment {
 6571      get { return comment_; }
 572    }
 573
 574    /// <summary>
 575    /// Gets the name of this zip file.
 576    /// </summary>
 577    public string Name {
 38578      get { return name_; }
 579    }
 580
 581    /// <summary>
 582    /// Gets the number of entries in this zip file.
 583    /// </summary>
 584    /// <exception cref="InvalidOperationException">
 585    /// The Zip file has been closed.
 586    /// </exception>
 587    [Obsolete("Use the Count property instead")]
 588    public int Size {
 589      get {
 0590        return entries_.Length;
 591      }
 592    }
 593
 594    /// <summary>
 595    /// Get the number of entries contained in this <see cref="ZipFile"/>.
 596    /// </summary>
 597    public long Count {
 598      get {
 66100599        return entries_.Length;
 600      }
 601    }
 602
 603    /// <summary>
 604    /// Indexer property for ZipEntries
 605    /// </summary>
 606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
 607    public ZipEntry this[int index] {
 608      get {
 329670609        return (ZipEntry)entries_[index].Clone();
 610      }
 611    }
 612
 613    #endregion
 614
 615    #region Input Handling
 616    /// <summary>
 617    /// Gets an enumerator for the Zip entries in this Zip file.
 618    /// </summary>
 619    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>
 620    /// <exception cref="ObjectDisposedException">
 621    /// The Zip file has been closed.
 622    /// </exception>
 623    public IEnumerator GetEnumerator()
 624    {
 4625       if (isDisposed_) {
 0626        throw new ObjectDisposedException("ZipFile");
 627      }
 628
 4629      return new ZipEntryEnumerator(entries_);
 630    }
 631
 632    /// <summary>
 633    /// Return the index of the entry with a matching name
 634    /// </summary>
 635    /// <param name="name">Entry name to find</param>
 636    /// <param name="ignoreCase">If true the comparison is case insensitive</param>
 637    /// <returns>The index position of the matching entry or -1 if not found</returns>
 638    /// <exception cref="ObjectDisposedException">
 639    /// The Zip file has been closed.
 640    /// </exception>
 641    public int FindEntry(string name, bool ignoreCase)
 642    {
 12643       if (isDisposed_) {
 0644        throw new ObjectDisposedException("ZipFile");
 645      }
 646
 647      // TODO: This will be slow as the next ice age for huge archives!
 62648       for (int i = 0; i < entries_.Length; i++) {
 28649         if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {
 9650          return i;
 651        }
 652      }
 3653      return -1;
 654    }
 655
 656    /// <summary>
 657    /// Searches for a zip entry in this archive with the given name.
 658    /// String comparisons are case insensitive
 659    /// </summary>
 660    /// <param name="name">
 661    /// The name to find. May contain directory components separated by slashes ('/').
 662    /// </param>
 663    /// <returns>
 664    /// A clone of the zip entry, or null if no entry with that name exists.
 665    /// </returns>
 666    /// <exception cref="ObjectDisposedException">
 667    /// The Zip file has been closed.
 668    /// </exception>
 669    public ZipEntry GetEntry(string name)
 670    {
 0671       if (isDisposed_) {
 0672        throw new ObjectDisposedException("ZipFile");
 673      }
 674
 0675      int index = FindEntry(name, true);
 0676       return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;
 677    }
 678
 679    /// <summary>
 680    /// Gets an input stream for reading the given zip entry data in an uncompressed form.
 681    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
 682    /// </summary>
 683    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
 684    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
 685    /// <exception cref="ObjectDisposedException">
 686    /// The ZipFile has already been closed
 687    /// </exception>
 688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 689    /// The compression method for the entry is unknown
 690    /// </exception>
 691    /// <exception cref="IndexOutOfRangeException">
 692    /// The entry is not found in the ZipFile
 693    /// </exception>
 694    public Stream GetInputStream(ZipEntry entry)
 695    {
 65933696       if (entry == null) {
 0697        throw new ArgumentNullException(nameof(entry));
 698      }
 699
 65933700       if (isDisposed_) {
 0701        throw new ObjectDisposedException("ZipFile");
 702      }
 703
 65933704      long index = entry.ZipFileIndex;
 65933705       if ((index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name)) {
 0706        index = FindEntry(entry.Name, true);
 0707         if (index < 0) {
 0708          throw new ZipException("Entry cannot be found");
 709        }
 710      }
 65933711      return GetInputStream(index);
 712    }
 713
 714    /// <summary>
 715    /// Creates an input stream reading a zip entry
 716    /// </summary>
 717    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
 718    /// <returns>
 719    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>
 720    /// </returns>
 721    /// <exception cref="ObjectDisposedException">
 722    /// The ZipFile has already been closed
 723    /// </exception>
 724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 725    /// The compression method for the entry is unknown
 726    /// </exception>
 727    /// <exception cref="IndexOutOfRangeException">
 728    /// The entry is not found in the ZipFile
 729    /// </exception>
 730    public Stream GetInputStream(long entryIndex)
 731    {
 65946732       if (isDisposed_) {
 0733        throw new ObjectDisposedException("ZipFile");
 734      }
 735
 65946736      long start = LocateEntry(entries_[entryIndex]);
 65946737      CompressionMethod method = entries_[entryIndex].CompressionMethod;
 65946738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);
 739
 65946740       if (entries_[entryIndex].IsCrypted == true) {
 10741        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);
 10742         if (result == null) {
 0743          throw new ZipException("Unable to decrypt this entry");
 744        }
 745      }
 746
 65946747       switch (method) {
 748        case CompressionMethod.Stored:
 749          // read as is.
 750          break;
 751
 752        case CompressionMethod.Deflated:
 753          // No need to worry about ownership and closing as underlying stream close does nothing.
 353754          result = new InflaterInputStream(result, new Inflater(true));
 353755          break;
 756
 757        default:
 0758          throw new ZipException("Unsupported compression method " + method);
 759      }
 760
 65946761      return result;
 762    }
 763
 764    #endregion
 765
 766    #region Archive Testing
 767    /// <summary>
 768    /// Test an archive for integrity/validity
 769    /// </summary>
 770    /// <param name="testData">Perform low level data Crc check</param>
 771    /// <returns>true if all tests pass, false otherwise</returns>
 772    /// <remarks>Testing will terminate on the first error found.</remarks>
 773    public bool TestArchive(bool testData)
 774    {
 96775      return TestArchive(testData, TestStrategy.FindFirstError, null);
 776    }
 777
 778    /// <summary>
 779    /// Test an archive for integrity/validity
 780    /// </summary>
 781    /// <param name="testData">Perform low level data Crc check</param>
 782    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
 783    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
 784    /// <returns>true if all tests pass, false otherwise</returns>
 785    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>
 786    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
 787    {
 96788       if (isDisposed_) {
 0789        throw new ObjectDisposedException("ZipFile");
 790      }
 791
 96792      var status = new TestStatus(this);
 793
 96794       if (resultHandler != null) {
 0795        resultHandler(status, null);
 796      }
 797
 96798       HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;
 799
 96800      bool testing = true;
 801
 802      try {
 96803        int entryIndex = 0;
 804
 66012805         while (testing && (entryIndex < Count)) {
 65916806           if (resultHandler != null) {
 0807            status.SetEntry(this[entryIndex]);
 0808            status.SetOperation(TestOperation.EntryHeader);
 0809            resultHandler(status, null);
 810          }
 811
 812          try {
 65916813            TestLocalHeader(this[entryIndex], test);
 65916814          } catch (ZipException ex) {
 0815            status.AddError();
 816
 0817             if (resultHandler != null) {
 0818              resultHandler(status,
 0819                string.Format("Exception during test - '{0}'", ex.Message));
 820            }
 821
 0822            testing &= strategy != TestStrategy.FindFirstError;
 0823          }
 824
 65916825           if (testing && testData && this[entryIndex].IsFile) {
 65912826             if (resultHandler != null) {
 0827              status.SetOperation(TestOperation.EntryData);
 0828              resultHandler(status, null);
 829            }
 830
 65912831            var crc = new Crc32();
 832
 65912833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {
 834
 65912835              byte[] buffer = new byte[4096];
 65912836              long totalBytes = 0;
 837              int bytesRead;
 66297838               while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
 385839                crc.Update(buffer, 0, bytesRead);
 840
 385841                 if (resultHandler != null) {
 0842                  totalBytes += bytesRead;
 0843                  status.SetBytesTested(totalBytes);
 0844                  resultHandler(status, null);
 845                }
 846              }
 65912847            }
 848
 65912849             if (this[entryIndex].Crc != crc.Value) {
 1850              status.AddError();
 851
 1852               if (resultHandler != null) {
 0853                resultHandler(status, "CRC mismatch");
 854              }
 855
 1856              testing &= strategy != TestStrategy.FindFirstError;
 857            }
 858
 65912859             if ((this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 13860              var helper = new ZipHelperStream(baseStream_);
 13861              var data = new DescriptorData();
 13862              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
 13863               if (this[entryIndex].Crc != data.Crc) {
 0864                status.AddError();
 865              }
 866
 13867               if (this[entryIndex].CompressedSize != data.CompressedSize) {
 0868                status.AddError();
 869              }
 870
 13871               if (this[entryIndex].Size != data.Size) {
 0872                status.AddError();
 873              }
 874            }
 875          }
 876
 65916877           if (resultHandler != null) {
 0878            status.SetOperation(TestOperation.EntryComplete);
 0879            resultHandler(status, null);
 880          }
 881
 65916882          entryIndex += 1;
 883        }
 884
 96885         if (resultHandler != null) {
 0886          status.SetOperation(TestOperation.MiscellaneousTests);
 0887          resultHandler(status, null);
 888        }
 889
 890        // TODO: the 'Corrina Johns' test where local headers are missing from
 891        // the central directory.  They are therefore invisible to many archivers.
 96892      } catch (Exception ex) {
 0893        status.AddError();
 894
 0895         if (resultHandler != null) {
 0896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
 897        }
 0898      }
 899
 96900       if (resultHandler != null) {
 0901        status.SetOperation(TestOperation.Complete);
 0902        status.SetEntry(null);
 0903        resultHandler(status, null);
 904      }
 905
 96906      return (status.ErrorCount == 0);
 907    }
 908
 909    [Flags]
 910    enum HeaderTest
 911    {
 912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted
 913      Header = 0x02,     // Check that this header contents are valid
 914    }
 915
 916    /// <summary>
 917    /// Test a local header against that provided from the central directory
 918    /// </summary>
 919    /// <param name="entry">
 920    /// The entry to test against
 921    /// </param>
 922    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
 923    /// <returns>The offset of the entries data in the file</returns>
 924    long TestLocalHeader(ZipEntry entry, HeaderTest tests)
 925    {
 131862926      lock (baseStream_) {
 131862927        bool testHeader = (tests & HeaderTest.Header) != 0;
 131862928        bool testData = (tests & HeaderTest.Extract) != 0;
 929
 131862930        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
 131862931         if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
 0932          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)
 933        }
 934
 131862935        var extractVersion = (short)(ReadLEUshort() & 0x00ff);
 131862936        var localFlags = (short)ReadLEUshort();
 131862937        var compressionMethod = (short)ReadLEUshort();
 131862938        var fileTime = (short)ReadLEUshort();
 131862939        var fileDate = (short)ReadLEUshort();
 131862940        uint crcValue = ReadLEUint();
 131862941        long compressedSize = ReadLEUint();
 131862942        long size = ReadLEUint();
 131862943        int storedNameLength = ReadLEUshort();
 131862944        int extraDataLength = ReadLEUshort();
 945
 131862946        byte[] nameData = new byte[storedNameLength];
 131862947        StreamUtils.ReadFully(baseStream_, nameData);
 948
 131862949        byte[] extraData = new byte[extraDataLength];
 131862950        StreamUtils.ReadFully(baseStream_, extraData);
 951
 131862952        var localExtraData = new ZipExtraData(extraData);
 953
 954        // Extra data / zip64 checks
 131862955         if (localExtraData.Find(1)) {
 956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
 957          // and size or compressedSize = MaxValue, due to rogue creators.
 958
 50959          size = localExtraData.ReadLong();
 50960          compressedSize = localExtraData.ReadLong();
 961
 50962           if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {
 963            // These may be valid if patched later
 9964             if ((size != -1) && (size != entry.Size)) {
 0965              throw new ZipException("Size invalid for descriptor");
 966            }
 967
 9968             if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {
 0969              throw new ZipException("Compressed size invalid for descriptor");
 970            }
 971          }
 972        } else {
 973          // No zip64 extra data but entry requires it.
 131812974           if ((extractVersion >= ZipConstants.VersionZip64) &&
 131812975            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) {
 0976            throw new ZipException("Required Zip64 extended information missing");
 977          }
 978        }
 979
 131862980         if (testData) {
 131862981           if (entry.IsFile) {
 131858982             if (!entry.IsCompressionMethodSupported()) {
 0983              throw new ZipException("Compression method not supported");
 984            }
 985
 131858986             if ((extractVersion > ZipConstants.VersionMadeBy)
 131858987              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64))) {
 0988              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract
 989            }
 990
 131858991             if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance
 0992              throw new ZipException("The library does not support the zip version required to extract this entry");
 993            }
 994          }
 995        }
 996
 131862997         if (testHeader) {
 65916998           if ((extractVersion <= 63) &&   // Ignore later versions as we dont know about them..
 65916999            (extractVersion != 10) &&
 659161000            (extractVersion != 11) &&
 659161001            (extractVersion != 20) &&
 659161002            (extractVersion != 21) &&
 659161003            (extractVersion != 25) &&
 659161004            (extractVersion != 27) &&
 659161005            (extractVersion != 45) &&
 659161006            (extractVersion != 46) &&
 659161007            (extractVersion != 50) &&
 659161008            (extractVersion != 51) &&
 659161009            (extractVersion != 52) &&
 659161010            (extractVersion != 61) &&
 659161011            (extractVersion != 62) &&
 659161012            (extractVersion != 63)
 659161013            ) {
 01014            throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersi
 1015          }
 1016
 1017          // Local entry flags dont have reserved bit set on.
 659161018           if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R
 01019            throw new ZipException("Reserved bit flags cannot be set.");
 1020          }
 1021
 1022          // Encryption requires extract version >= 20
 659161023           if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) {
 01024            throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})
 1025          }
 1026
 1027          // Strong encryption requires encryption flag to be set and extract version >= 50.
 659161028           if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 01029             if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) {
 01030              throw new ZipException("Strong encryption flag set but encryption flag is not set");
 1031            }
 1032
 01033             if (extractVersion < 50) {
 01034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0
 1035            }
 1036          }
 1037
 1038          // Patched entries require extract version >= 27
 659161039           if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {
 01040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
 1041          }
 1042
 1043          // Central header flags match local entry flags.
 659161044           if (localFlags != entry.Flags) {
 01045            throw new ZipException("Central header/local header flags mismatch");
 1046          }
 1047
 1048          // Central header compression method matches local entry
 659161049           if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {
 01050            throw new ZipException("Central header/local header compression method mismatch");
 1051          }
 1052
 659161053           if (entry.Version != extractVersion) {
 01054            throw new ZipException("Extract version mismatch");
 1055          }
 1056
 1057          // Strong encryption and extract version match
 659161058           if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) {
 01059             if (extractVersion < 62) {
 01060              throw new ZipException("Strong encryption flag set but version not high enough");
 1061            }
 1062          }
 1063
 659161064           if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) {
 01065             if ((fileTime != 0) || (fileDate != 0)) {
 01066              throw new ZipException("Header masked set but date/time values non-zero");
 1067            }
 1068          }
 1069
 659161070           if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
 659001071             if (crcValue != (uint)entry.Crc) {
 01072              throw new ZipException("Central header/local header crc mismatch");
 1073            }
 1074          }
 1075
 1076          // Crc valid for empty entry.
 1077          // This will also apply to streamed entries where size isnt known and the header cant be patched
 659161078           if ((size == 0) && (compressedSize == 0)) {
 655411079             if (crcValue != 0) {
 01080              throw new ZipException("Invalid CRC for empty entry");
 1081            }
 1082          }
 1083
 1084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str
 1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
 659161086           if (entry.Name.Length > storedNameLength) {
 01087            throw new ZipException("File name length mismatch");
 1088          }
 1089
 1090          // Name data has already been read convert it and compare.
 659161091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);
 1092
 1093          // Central directory and local entry name match
 659161094           if (localName != entry.Name) {
 01095            throw new ZipException("Central header and local header file name mismatch");
 1096          }
 1097
 1098          // Directories have zero actual size but can have compressed size
 659161099           if (entry.IsDirectory) {
 41100             if (size > 0) {
 01101              throw new ZipException("Directory cannot have size");
 1102            }
 1103
 1104            // There may be other cases where the compressed size can be greater than this?
 1105            // If so until details are known we will be strict.
 41106             if (entry.IsCrypted) {
 21107               if (compressedSize > ZipConstants.CryptoHeaderSize + 2) {
 01108                throw new ZipException("Directory compressed size invalid");
 1109              }
 21110             } else if (compressedSize > 2) {
 1111              // When not compressed the directory size can validly be 2 bytes
 1112              // if the true size wasnt known when data was originally being written.
 1113              // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
 01114              throw new ZipException("Directory compressed size invalid");
 1115            }
 1116          }
 1117
 659161118           if (!ZipNameTransform.IsValidName(localName, true)) {
 01119            throw new ZipException("Name is invalid");
 1120          }
 1121        }
 1122
 1123        // Tests that apply to both data and header.
 1124
 1125        // Size can be verified only if it is known in the local header.
 1126        // it will always be known in the central header.
 1318621127         if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
 1318621128          ((size > 0 || compressedSize > 0) && entry.Size > 0)) {
 1129
 1318471130           if ((size != 0)
 1318471131            && (size != entry.Size)) {
 01132            throw new ZipException(
 01133              string.Format("Size mismatch between central header({0}) and local header({1})",
 01134                entry.Size, size));
 1135          }
 1136
 1318471137           if ((compressedSize != 0)
 1318471138            && (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) {
 01139            throw new ZipException(
 01140              string.Format("Compressed size mismatch between central header({0}) and local header({1})",
 01141              entry.CompressedSize, compressedSize));
 1142          }
 1143        }
 1144
 1318621145        int extraLength = storedNameLength + extraDataLength;
 1318621146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
 1147      }
 1318621148    }
 1149
 1150    #endregion
 1151
 1152    #region Updating
 1153
 1154    const int DefaultBufferSize = 4096;
 1155
 1156    /// <summary>
 1157    /// The kind of update to apply.
 1158    /// </summary>
 1159    enum UpdateCommand
 1160    {
 1161      Copy,       // Copy original file contents.
 1162      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.
 1163      Add,        // Add a new file to the archive.
 1164    }
 1165
 1166    #region Properties
 1167    /// <summary>
 1168    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.
 1169    /// </summary>
 1170    public INameTransform NameTransform {
 1171      get {
 657401172        return updateEntryFactory_.NameTransform;
 1173      }
 1174
 1175      set {
 01176        updateEntryFactory_.NameTransform = value;
 01177      }
 1178    }
 1179
 1180    /// <summary>
 1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values
 1182    /// during updates.
 1183    /// </summary>
 1184    public IEntryFactory EntryFactory {
 1185      get {
 1721186        return updateEntryFactory_;
 1187      }
 1188
 1189      set {
 01190         if (value == null) {
 01191          updateEntryFactory_ = new ZipEntryFactory();
 01192        } else {
 01193          updateEntryFactory_ = value;
 1194        }
 01195      }
 1196    }
 1197
 1198    /// <summary>
 1199    /// Get /set the buffer size to be used when updating this zip file.
 1200    /// </summary>
 1201    public int BufferSize {
 01202      get { return bufferSize_; }
 1203      set {
 01204         if (value < 1024) {
 01205          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");
 1206        }
 1207
 01208         if (bufferSize_ != value) {
 01209          bufferSize_ = value;
 01210          copyBuffer_ = null;
 1211        }
 01212      }
 1213    }
 1214
 1215    /// <summary>
 1216    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.
 1217    /// </summary>
 1218    public bool IsUpdating {
 01219      get { return updates_ != null; }
 1220    }
 1221
 1222    /// <summary>
 1223    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
 1224    /// </summary>
 1225    public UseZip64 UseZip64 {
 31226      get { return useZip64_; }
 121227      set { useZip64_ = value; }
 1228    }
 1229
 1230    #endregion
 1231
 1232    #region Immediate updating
 1233    //    TBD: Direct form of updating
 1234    //
 1235    //    public void Update(IEntryMatcher deleteMatcher)
 1236    //    {
 1237    //    }
 1238    //
 1239    //    public void Update(IScanner addScanner)
 1240    //    {
 1241    //    }
 1242    #endregion
 1243
 1244    #region Deferred Updating
 1245    /// <summary>
 1246    /// Begin updating this <see cref="ZipFile"/> archive.
 1247    /// </summary>
 1248    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p
 1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param
 1250    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1251    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>
 1252    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1253    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)
 1254    {
 481255       if (archiveStorage == null) {
 01256        throw new ArgumentNullException(nameof(archiveStorage));
 1257      }
 1258
 481259       if (dataSource == null) {
 01260        throw new ArgumentNullException(nameof(dataSource));
 1261      }
 1262
 481263       if (isDisposed_) {
 01264        throw new ObjectDisposedException("ZipFile");
 1265      }
 1266
 481267       if (IsEmbeddedArchive) {
 01268        throw new ZipException("Cannot update embedded/SFX archives");
 1269      }
 1270
 481271      archiveStorage_ = archiveStorage;
 481272      updateDataSource_ = dataSource;
 1273
 1274      // NOTE: the baseStream_ may not currently support writing or seeking.
 1275
 481276      updateIndex_ = new Hashtable();
 1277
 481278      updates_ = new ArrayList(entries_.Length);
 3181279      foreach (ZipEntry entry in entries_) {
 1111280        int index = updates_.Add(new ZipUpdate(entry));
 1111281        updateIndex_.Add(entry.Name, index);
 1282      }
 1283
 1284      // We must sort by offset before using offset's calculated sizes
 481285      updates_.Sort(new UpdateComparer());
 1286
 481287      int idx = 0;
 2871288      foreach (ZipUpdate update in updates_) {
 1289        //If last entry, there is no next entry offset to use
 1111290         if (idx == updates_.Count - 1)
 311291          break;
 1292
 801293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;
 801294        idx++;
 1295      }
 481296      updateCount_ = updates_.Count;
 1297
 481298      contentsEdited_ = false;
 481299      commentEdited_ = false;
 481300      newComment_ = null;
 481301    }
 1302
 1303    /// <summary>
 1304    /// Begin updating to this <see cref="ZipFile"/> archive.
 1305    /// </summary>
 1306    /// <param name="archiveStorage">The storage to use during the update.</param>
 1307    public void BeginUpdate(IArchiveStorage archiveStorage)
 1308    {
 321309      BeginUpdate(archiveStorage, new DynamicDiskDataSource());
 321310    }
 1311
 1312    /// <summary>
 1313    /// Begin updating this <see cref="ZipFile"/> archive.
 1314    /// </summary>
 1315    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>
 1316    /// <seealso cref="CommitUpdate"></seealso>
 1317    /// <seealso cref="AbortUpdate"></seealso>
 1318    public void BeginUpdate()
 1319    {
 161320       if (Name == null) {
 61321        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());
 61322      } else {
 101323        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());
 1324      }
 101325    }
 1326
 1327    /// <summary>
 1328    /// Commit current updates, updating this archive.
 1329    /// </summary>
 1330    /// <seealso cref="BeginUpdate()"></seealso>
 1331    /// <seealso cref="AbortUpdate"></seealso>
 1332    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1333    public void CommitUpdate()
 1334    {
 481335       if (isDisposed_) {
 01336        throw new ObjectDisposedException("ZipFile");
 1337      }
 1338
 481339      CheckUpdating();
 1340
 1341      try {
 481342        updateIndex_.Clear();
 481343        updateIndex_ = null;
 1344
 481345         if (contentsEdited_) {
 441346          RunUpdates();
 481347         } else if (commentEdited_) {
 31348          UpdateCommentOnly();
 31349        } else {
 1350          // Create an empty archive if none existed originally.
 11351           if (entries_.Length == 0) {
 11352            byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 11353            using (ZipHelperStream zhs = new ZipHelperStream(baseStream_)) {
 11354              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
 11355            }
 1356          }
 1357        }
 1358
 01359      } finally {
 481360        PostUpdateCleanup();
 481361      }
 481362    }
 1363
 1364    /// <summary>
 1365    /// Abort updating leaving the archive unchanged.
 1366    /// </summary>
 1367    /// <seealso cref="BeginUpdate()"></seealso>
 1368    /// <seealso cref="CommitUpdate"></seealso>
 1369    public void AbortUpdate()
 1370    {
 01371      PostUpdateCleanup();
 01372    }
 1373
 1374    /// <summary>
 1375    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.
 1376    /// </summary>
 1377    /// <param name="comment">The comment to record.</param>
 1378    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1379    public void SetComment(string comment)
 1380    {
 31381       if (isDisposed_) {
 01382        throw new ObjectDisposedException("ZipFile");
 1383      }
 1384
 31385      CheckUpdating();
 1386
 31387      newComment_ = new ZipString(comment);
 1388
 31389       if (newComment_.RawLength > 0xffff) {
 01390        newComment_ = null;
 01391        throw new ZipException("Comment length exceeds maximum - 65535");
 1392      }
 1393
 1394      // We dont take account of the original and current comment appearing to be the same
 1395      // as encoding may be different.
 31396      commentEdited_ = true;
 31397    }
 1398
 1399    #endregion
 1400
 1401    #region Adding Entries
 1402
 1403    void AddUpdate(ZipUpdate update)
 1404    {
 657051405      contentsEdited_ = true;
 1406
 657051407      int index = FindExistingUpdate(update.Entry.Name);
 1408
 657051409       if (index >= 0) {
 01410         if (updates_[index] == null) {
 01411          updateCount_ += 1;
 1412        }
 1413
 1414        // Direct replacement is faster than delete and add.
 01415        updates_[index] = update;
 01416      } else {
 657051417        index = updates_.Add(update);
 657051418        updateCount_ += 1;
 657051419        updateIndex_.Add(update.Entry.Name, index);
 1420      }
 657051421    }
 1422
 1423    /// <summary>
 1424    /// Add a new entry to the archive.
 1425    /// </summary>
 1426    /// <param name="fileName">The name of the file to add.</param>
 1427    /// <param name="compressionMethod">The compression method to use.</param>
 1428    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>
 1429    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1430    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
 1431    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>
 1432    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText)
 1433    {
 01434       if (fileName == null) {
 01435        throw new ArgumentNullException(nameof(fileName));
 1436      }
 1437
 01438       if (isDisposed_) {
 01439        throw new ObjectDisposedException("ZipFile");
 1440      }
 1441
 01442       if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 01443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1444      }
 1445
 01446      CheckUpdating();
 01447      contentsEdited_ = true;
 1448
 01449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 01450      entry.IsUnicodeText = useUnicodeText;
 01451      entry.CompressionMethod = compressionMethod;
 1452
 01453      AddUpdate(new ZipUpdate(fileName, entry));
 01454    }
 1455
 1456    /// <summary>
 1457    /// Add a new entry to the archive.
 1458    /// </summary>
 1459    /// <param name="fileName">The name of the file to add.</param>
 1460    /// <param name="compressionMethod">The compression method to use.</param>
 1461    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>
 1462    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>
 1463    public void Add(string fileName, CompressionMethod compressionMethod)
 1464    {
 01465       if (fileName == null) {
 01466        throw new ArgumentNullException(nameof(fileName));
 1467      }
 1468
 01469       if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
 01470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));
 1471      }
 1472
 01473      CheckUpdating();
 01474      contentsEdited_ = true;
 1475
 01476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
 01477      entry.CompressionMethod = compressionMethod;
 01478      AddUpdate(new ZipUpdate(fileName, entry));
 01479    }
 1480
 1481    /// <summary>
 1482    /// Add a file to the archive.
 1483    /// </summary>
 1484    /// <param name="fileName">The name of the file to add.</param>
 1485    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1486    public void Add(string fileName)
 1487    {
 31488       if (fileName == null) {
 01489        throw new ArgumentNullException(nameof(fileName));
 1490      }
 1491
 31492      CheckUpdating();
 31493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));
 31494    }
 1495
 1496    /// <summary>
 1497    /// Add a file to the archive.
 1498    /// </summary>
 1499    /// <param name="fileName">The name of the file to add.</param>
 1500    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>
 1501    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>
 1502    public void Add(string fileName, string entryName)
 1503    {
 01504       if (fileName == null) {
 01505        throw new ArgumentNullException(nameof(fileName));
 1506      }
 1507
 01508       if (entryName == null) {
 01509        throw new ArgumentNullException(nameof(entryName));
 1510      }
 1511
 01512      CheckUpdating();
 01513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));
 01514    }
 1515
 1516
 1517    /// <summary>
 1518    /// Add a file entry with data.
 1519    /// </summary>
 1520    /// <param name="dataSource">The source of the data for this entry.</param>
 1521    /// <param name="entryName">The name to give to the entry.</param>
 1522    public void Add(IStaticDataSource dataSource, string entryName)
 1523    {
 1461524       if (dataSource == null) {
 01525        throw new ArgumentNullException(nameof(dataSource));
 1526      }
 1527
 1461528       if (entryName == null) {
 01529        throw new ArgumentNullException(nameof(entryName));
 1530      }
 1531
 1461532      CheckUpdating();
 1461533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));
 1461534    }
 1535
 1536    /// <summary>
 1537    /// Add a file entry with data.
 1538    /// </summary>
 1539    /// <param name="dataSource">The source of the data for this entry.</param>
 1540    /// <param name="entryName">The name to give to the entry.</param>
 1541    /// <param name="compressionMethod">The compression method to use.</param>
 1542    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 1543    {
 151544       if (dataSource == null) {
 01545        throw new ArgumentNullException(nameof(dataSource));
 1546      }
 1547
 151548       if (entryName == null) {
 01549        throw new ArgumentNullException(nameof(entryName));
 1550      }
 1551
 151552      CheckUpdating();
 1553
 151554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 151555      entry.CompressionMethod = compressionMethod;
 1556
 151557      AddUpdate(new ZipUpdate(dataSource, entry));
 151558    }
 1559
 1560    /// <summary>
 1561    /// Add a file entry with data.
 1562    /// </summary>
 1563    /// <param name="dataSource">The source of the data for this entry.</param>
 1564    /// <param name="entryName">The name to give to the entry.</param>
 1565    /// <param name="compressionMethod">The compression method to use.</param>
 1566    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>
 1567    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode
 1568    {
 41569       if (dataSource == null) {
 01570        throw new ArgumentNullException(nameof(dataSource));
 1571      }
 1572
 41573       if (entryName == null) {
 01574        throw new ArgumentNullException(nameof(entryName));
 1575      }
 1576
 41577      CheckUpdating();
 1578
 41579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
 41580      entry.IsUnicodeText = useUnicodeText;
 41581      entry.CompressionMethod = compressionMethod;
 1582
 41583      AddUpdate(new ZipUpdate(dataSource, entry));
 41584    }
 1585
 1586    /// <summary>
 1587    /// Add a <see cref="ZipEntry"/> that contains no data.
 1588    /// </summary>
 1589    /// <param name="entry">The entry to add.</param>
 1590    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
 1591    public void Add(ZipEntry entry)
 1592    {
 655371593       if (entry == null) {
 01594        throw new ArgumentNullException(nameof(entry));
 1595      }
 1596
 655371597      CheckUpdating();
 1598
 655371599       if ((entry.Size != 0) || (entry.CompressedSize != 0)) {
 01600        throw new ZipException("Entry cannot have any data");
 1601      }
 1602
 655371603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
 655371604    }
 1605
 1606    /// <summary>
 1607    /// Add a directory entry to the archive.
 1608    /// </summary>
 1609    /// <param name="directoryName">The directory to add.</param>
 1610    public void AddDirectory(string directoryName)
 1611    {
 01612       if (directoryName == null) {
 01613        throw new ArgumentNullException(nameof(directoryName));
 1614      }
 1615
 01616      CheckUpdating();
 1617
 01618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);
 01619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));
 01620    }
 1621
 1622    #endregion
 1623
 1624    #region Modifying Entries
 1625    /* Modify not yet ready for public consumption.
 1626       Direct modification of an entry should not overwrite original data before its read.
 1627       Safe mode is trivial in this sense.
 1628        public void Modify(ZipEntry original, ZipEntry updated)
 1629        {
 1630          if ( original == null ) {
 1631            throw new ArgumentNullException("original");
 1632          }
 1633
 1634          if ( updated == null ) {
 1635            throw new ArgumentNullException("updated");
 1636          }
 1637
 1638          CheckUpdating();
 1639          contentsEdited_ = true;
 1640          updates_.Add(new ZipUpdate(original, updated));
 1641        }
 1642    */
 1643    #endregion
 1644
 1645    #region Deleting Entries
 1646    /// <summary>
 1647    /// Delete an entry by name
 1648    /// </summary>
 1649    /// <param name="fileName">The filename to delete</param>
 1650    /// <returns>True if the entry was found and deleted; false otherwise.</returns>
 1651    public bool Delete(string fileName)
 1652    {
 31653       if (fileName == null) {
 01654        throw new ArgumentNullException(nameof(fileName));
 1655      }
 1656
 31657      CheckUpdating();
 1658
 31659      bool result = false;
 31660      int index = FindExistingUpdate(fileName);
 31661       if ((index >= 0) && (updates_[index] != null)) {
 31662        result = true;
 31663        contentsEdited_ = true;
 31664        updates_[index] = null;
 31665        updateCount_ -= 1;
 31666      } else {
 01667        throw new ZipException("Cannot find entry to delete");
 1668      }
 31669      return result;
 1670    }
 1671
 1672    /// <summary>
 1673    /// Delete a <see cref="ZipEntry"/> from the archive.
 1674    /// </summary>
 1675    /// <param name="entry">The entry to delete.</param>
 1676    public void Delete(ZipEntry entry)
 1677    {
 321678       if (entry == null) {
 01679        throw new ArgumentNullException(nameof(entry));
 1680      }
 1681
 321682      CheckUpdating();
 1683
 321684      int index = FindExistingUpdate(entry);
 321685       if (index >= 0) {
 321686        contentsEdited_ = true;
 321687        updates_[index] = null;
 321688        updateCount_ -= 1;
 321689      } else {
 01690        throw new ZipException("Cannot find entry to delete");
 1691      }
 1692    }
 1693
 1694    #endregion
 1695
 1696    #region Update Support
 1697
 1698    #region Writing Values/Headers
 1699    void WriteLEShort(int value)
 1700    {
 22370481701      baseStream_.WriteByte((byte)(value & 0xff));
 22370481702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));
 22370481703    }
 1704
 1705    /// <summary>
 1706    /// Write an unsigned short in little endian byte order.
 1707    /// </summary>
 1708    void WriteLEUshort(ushort value)
 1709    {
 2629441710      baseStream_.WriteByte((byte)(value & 0xff));
 2629441711      baseStream_.WriteByte((byte)(value >> 8));
 2629441712    }
 1713
 1714    /// <summary>
 1715    /// Write an int in little endian byte order.
 1716    /// </summary>
 1717    void WriteLEInt(int value)
 1718    {
 6581801719      WriteLEShort(value & 0xffff);
 6581801720      WriteLEShort(value >> 16);
 6581801721    }
 1722
 1723    /// <summary>
 1724    /// Write an unsigned int in little endian byte order.
 1725    /// </summary>
 1726    void WriteLEUint(uint value)
 1727    {
 1314721728      WriteLEUshort((ushort)(value & 0xffff));
 1314721729      WriteLEUshort((ushort)(value >> 16));
 1314721730    }
 1731
 1732    /// <summary>
 1733    /// Write a long in little endian byte order.
 1734    /// </summary>
 1735    void WriteLeLong(long value)
 1736    {
 41737      WriteLEInt((int)(value & 0xffffffff));
 41738      WriteLEInt((int)(value >> 32));
 41739    }
 1740
 1741    void WriteLEUlong(ulong value)
 1742    {
 01743      WriteLEUint((uint)(value & 0xffffffff));
 01744      WriteLEUint((uint)(value >> 32));
 01745    }
 1746
 1747    void WriteLocalEntryHeader(ZipUpdate update)
 1748    {
 657481749      ZipEntry entry = update.OutEntry;
 1750
 1751      // TODO: Local offset will require adjusting for multi-disk zip files.
 657481752      entry.Offset = baseStream_.Position;
 1753
 1754      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
 657481755       if (update.Command != UpdateCommand.Copy) {
 657051756         if (entry.CompressionMethod == CompressionMethod.Deflated) {
 656901757           if (entry.Size == 0) {
 1758            // No need to compress - no data.
 655371759            entry.CompressedSize = entry.Size;
 655371760            entry.Crc = 0;
 655371761            entry.CompressionMethod = CompressionMethod.Stored;
 1762          }
 655521763         } else if (entry.CompressionMethod == CompressionMethod.Stored) {
 151764          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
 1765        }
 1766
 657051767         if (HaveKeys) {
 51768          entry.IsCrypted = true;
 51769           if (entry.Crc < 0) {
 51770            entry.Flags |= (int)GeneralBitFlags.Descriptor;
 1771          }
 51772        } else {
 657001773          entry.IsCrypted = false;
 1774        }
 1775
 657051776         switch (useZip64_) {
 1777          case UseZip64.Dynamic:
 657011778             if (entry.Size < 0) {
 01779              entry.ForceZip64();
 1780            }
 01781            break;
 1782
 1783          case UseZip64.On:
 21784            entry.ForceZip64();
 1785            break;
 1786
 1787          case UseZip64.Off:
 1788            // Do nothing.  The entry itself may be using Zip64 independantly.
 1789            break;
 1790        }
 1791      }
 1792
 1793      // Write the local file header
 657481794      WriteLEInt(ZipConstants.LocalHeaderSignature);
 1795
 657481796      WriteLEShort(entry.Version);
 657481797      WriteLEShort(entry.Flags);
 1798
 657481799      WriteLEShort((byte)entry.CompressionMethod);
 657481800      WriteLEInt((int)entry.DosTime);
 1801
 657481802       if (!entry.HasCrc) {
 1803        // Note patch address for updating CRC later.
 1681804        update.CrcPatchOffset = baseStream_.Position;
 1681805        WriteLEInt((int)0);
 1681806      } else {
 655801807        WriteLEInt(unchecked((int)entry.Crc));
 1808      }
 1809
 657481810       if (entry.LocalHeaderRequiresZip64) {
 21811        WriteLEInt(-1);
 21812        WriteLEInt(-1);
 21813      } else {
 657461814         if ((entry.CompressedSize < 0) || (entry.Size < 0)) {
 1661815          update.SizePatchOffset = baseStream_.Position;
 1816        }
 1817
 657461818        WriteLEInt((int)entry.CompressedSize);
 657461819        WriteLEInt((int)entry.Size);
 1820      }
 1821
 657481822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1823
 657481824       if (name.Length > 0xFFFF) {
 01825        throw new ZipException("Entry name too long.");
 1826      }
 1827
 657481828      var ed = new ZipExtraData(entry.ExtraData);
 1829
 657481830       if (entry.LocalHeaderRequiresZip64) {
 21831        ed.StartNewEntry();
 1832
 1833        // Local entry header always includes size and compressed size.
 1834        // NOTE the order of these fields is reversed when compared to the normal headers!
 21835        ed.AddLeLong(entry.Size);
 21836        ed.AddLeLong(entry.CompressedSize);
 21837        ed.AddNewEntry(1);
 21838      } else {
 657461839        ed.Delete(1);
 1840      }
 1841
 657481842      entry.ExtraData = ed.GetEntryData();
 1843
 657481844      WriteLEShort(name.Length);
 657481845      WriteLEShort(entry.ExtraData.Length);
 1846
 657481847       if (name.Length > 0) {
 657481848        baseStream_.Write(name, 0, name.Length);
 1849      }
 1850
 657481851       if (entry.LocalHeaderRequiresZip64) {
 21852         if (!ed.Find(1)) {
 01853          throw new ZipException("Internal error cannot find extra data");
 1854        }
 1855
 21856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
 1857      }
 1858
 657481859       if (entry.ExtraData.Length > 0) {
 21860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
 1861      }
 657481862    }
 1863
 1864    int WriteCentralDirectoryHeader(ZipEntry entry)
 1865    {
 657721866       if (entry.CompressedSize < 0) {
 01867        throw new ZipException("Attempt to write central directory entry with unknown csize");
 1868      }
 1869
 657721870       if (entry.Size < 0) {
 01871        throw new ZipException("Attempt to write central directory entry with unknown size");
 1872      }
 1873
 657721874       if (entry.Crc < 0) {
 01875        throw new ZipException("Attempt to write central directory entry with unknown crc");
 1876      }
 1877
 1878      // Write the central file header
 657721879      WriteLEInt(ZipConstants.CentralHeaderSignature);
 1880
 1881      // Version made by
 657721882      WriteLEShort(ZipConstants.VersionMadeBy);
 1883
 1884      // Version required to extract
 657721885      WriteLEShort(entry.Version);
 1886
 657721887      WriteLEShort(entry.Flags);
 1888
 1889      unchecked {
 657721890        WriteLEShort((byte)entry.CompressionMethod);
 657721891        WriteLEInt((int)entry.DosTime);
 657721892        WriteLEInt((int)entry.Crc);
 1893      }
 1894
 657721895       if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {
 21896        WriteLEInt(-1);
 21897      } else {
 657701898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
 1899      }
 1900
 657721901       if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {
 21902        WriteLEInt(-1);
 21903      } else {
 657701904        WriteLEInt((int)entry.Size);
 1905      }
 1906
 657721907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 1908
 657721909       if (name.Length > 0xFFFF) {
 01910        throw new ZipException("Entry name is too long.");
 1911      }
 1912
 657721913      WriteLEShort(name.Length);
 1914
 1915      // Central header extra data is different to local header version so regenerate.
 657721916      var ed = new ZipExtraData(entry.ExtraData);
 1917
 657721918       if (entry.CentralHeaderRequiresZip64) {
 21919        ed.StartNewEntry();
 1920
 21921         if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 21922          ed.AddLeLong(entry.Size);
 1923        }
 1924
 21925         if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {
 21926          ed.AddLeLong(entry.CompressedSize);
 1927        }
 1928
 21929         if (entry.Offset >= 0xffffffff) {
 01930          ed.AddLeLong(entry.Offset);
 1931        }
 1932
 1933        // Number of disk on which this file starts isnt supported and is never written here.
 21934        ed.AddNewEntry(1);
 21935      } else {
 1936        // Should have already be done when local header was added.
 657701937        ed.Delete(1);
 1938      }
 1939
 657721940      byte[] centralExtraData = ed.GetEntryData();
 1941
 657721942      WriteLEShort(centralExtraData.Length);
 657721943       WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);
 1944
 657721945      WriteLEShort(0);    // disk number
 657721946      WriteLEShort(0);    // internal file attributes
 1947
 1948      // External file attributes...
 657721949       if (entry.ExternalFileAttributes != -1) {
 721950        WriteLEInt(entry.ExternalFileAttributes);
 721951      } else {
 657001952         if (entry.IsDirectory) {
 01953          WriteLEUint(16);
 01954        } else {
 657001955          WriteLEUint(0);
 1956        }
 1957      }
 1958
 657721959       if (entry.Offset >= 0xffffffff) {
 01960        WriteLEUint(0xffffffff);
 01961      } else {
 657721962        WriteLEUint((uint)(int)entry.Offset);
 1963      }
 1964
 657721965       if (name.Length > 0) {
 657721966        baseStream_.Write(name, 0, name.Length);
 1967      }
 1968
 657721969       if (centralExtraData.Length > 0) {
 21970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
 1971      }
 1972
 657721973       byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];
 1974
 657721975       if (rawComment.Length > 0) {
 01976        baseStream_.Write(rawComment, 0, rawComment.Length);
 1977      }
 1978
 657721979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
 1980    }
 1981    #endregion
 1982
 1983    void PostUpdateCleanup()
 1984    {
 1361985      updateDataSource_ = null;
 1361986      updates_ = null;
 1361987      updateIndex_ = null;
 1988
 1361989       if (archiveStorage_ != null) {
 481990        archiveStorage_.Dispose();
 481991        archiveStorage_ = null;
 1992      }
 1361993    }
 1994
 1995    string GetTransformedFileName(string name)
 1996    {
 657401997      INameTransform transform = NameTransform;
 657401998       return (transform != null) ?
 657401999        transform.TransformFile(name) :
 657402000        name;
 2001    }
 2002
 2003    string GetTransformedDirectoryName(string name)
 2004    {
 02005      INameTransform transform = NameTransform;
 02006       return (transform != null) ?
 02007        transform.TransformDirectory(name) :
 02008        name;
 2009    }
 2010
 2011    /// <summary>
 2012    /// Get a raw memory buffer.
 2013    /// </summary>
 2014    /// <returns>Returns a raw memory buffer.</returns>
 2015    byte[] GetBuffer()
 2016    {
 2112017       if (copyBuffer_ == null) {
 412018        copyBuffer_ = new byte[bufferSize_];
 2019      }
 2112020      return copyBuffer_;
 2021    }
 2022
 2023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)
 2024    {
 42025      int bytesToCopy = GetDescriptorSize(update);
 2026
 42027       if (bytesToCopy > 0) {
 02028        byte[] buffer = GetBuffer();
 2029
 02030         while (bytesToCopy > 0) {
 02031          int readSize = Math.Min(buffer.Length, bytesToCopy);
 2032
 02033          int bytesRead = source.Read(buffer, 0, readSize);
 02034           if (bytesRead > 0) {
 02035            dest.Write(buffer, 0, bytesRead);
 02036            bytesToCopy -= bytesRead;
 02037          } else {
 02038            throw new ZipException("Unxpected end of stream");
 2039          }
 2040        }
 2041      }
 42042    }
 2043
 2044    void CopyBytes(ZipUpdate update, Stream destination, Stream source,
 2045      long bytesToCopy, bool updateCrc)
 2046    {
 1722047       if (destination == source) {
 02048        throw new InvalidOperationException("Destination and source are the same");
 2049      }
 2050
 2051      // NOTE: Compressed size is updated elsewhere.
 1722052      var crc = new Crc32();
 1722053      byte[] buffer = GetBuffer();
 2054
 1722055      long targetBytes = bytesToCopy;
 1722056      long totalBytesRead = 0;
 2057
 2058      int bytesRead;
 2059      do {
 1722060        int readSize = buffer.Length;
 2061
 1722062         if (bytesToCopy < readSize) {
 1722063          readSize = (int)bytesToCopy;
 2064        }
 2065
 1722066        bytesRead = source.Read(buffer, 0, readSize);
 1722067         if (bytesRead > 0) {
 1722068           if (updateCrc) {
 1682069            crc.Update(buffer, 0, bytesRead);
 2070          }
 1722071          destination.Write(buffer, 0, bytesRead);
 1722072          bytesToCopy -= bytesRead;
 1722073          totalBytesRead += bytesRead;
 2074        }
 2075      }
 1722076       while ((bytesRead > 0) && (bytesToCopy > 0));
 2077
 1722078       if (totalBytesRead != targetBytes) {
 02079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2080      }
 2081
 1722082       if (updateCrc) {
 1682083        update.OutEntry.Crc = crc.Value;
 2084      }
 1722085    }
 2086
 2087    /// <summary>
 2088    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
 2089    /// </summary>
 2090    /// <param name="update">The update to get the size for.</param>
 2091    /// <returns>The descriptor size, zero if there isnt one.</returns>
 2092    int GetDescriptorSize(ZipUpdate update)
 2093    {
 452094      int result = 0;
 452095       if ((update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 02096        result = ZipConstants.DataDescriptorSize - 4;
 02097         if (update.Entry.LocalHeaderRequiresZip64) {
 02098          result = ZipConstants.Zip64DataDescriptorSize - 4;
 2099        }
 2100      }
 452101      return result;
 2102    }
 2103
 2104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
 2105    {
 392106      int bytesToCopy = GetDescriptorSize(update);
 2107
 392108       while (bytesToCopy > 0) {
 02109        var readSize = (int)bytesToCopy;
 02110        byte[] buffer = GetBuffer();
 2111
 02112        stream.Position = sourcePosition;
 02113        int bytesRead = stream.Read(buffer, 0, readSize);
 02114         if (bytesRead > 0) {
 02115          stream.Position = destinationPosition;
 02116          stream.Write(buffer, 0, bytesRead);
 02117          bytesToCopy -= bytesRead;
 02118          destinationPosition += bytesRead;
 02119          sourcePosition += bytesRead;
 02120        } else {
 02121          throw new ZipException("Unxpected end of stream");
 2122        }
 2123      }
 392124    }
 2125
 2126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou
 2127    {
 392128      long bytesToCopy = update.Entry.CompressedSize;
 2129
 2130      // NOTE: Compressed size is updated elsewhere.
 392131      var crc = new Crc32();
 392132      byte[] buffer = GetBuffer();
 2133
 392134      long targetBytes = bytesToCopy;
 392135      long totalBytesRead = 0;
 2136
 2137      int bytesRead;
 2138      do {
 392139        int readSize = buffer.Length;
 2140
 392141         if (bytesToCopy < readSize) {
 392142          readSize = (int)bytesToCopy;
 2143        }
 2144
 392145        stream.Position = sourcePosition;
 392146        bytesRead = stream.Read(buffer, 0, readSize);
 392147         if (bytesRead > 0) {
 392148           if (updateCrc) {
 02149            crc.Update(buffer, 0, bytesRead);
 2150          }
 392151          stream.Position = destinationPosition;
 392152          stream.Write(buffer, 0, bytesRead);
 2153
 392154          destinationPosition += bytesRead;
 392155          sourcePosition += bytesRead;
 392156          bytesToCopy -= bytesRead;
 392157          totalBytesRead += bytesRead;
 2158        }
 2159      }
 392160       while ((bytesRead > 0) && (bytesToCopy > 0));
 2161
 392162       if (totalBytesRead != targetBytes) {
 02163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))
 2164      }
 2165
 392166       if (updateCrc) {
 02167        update.OutEntry.Crc = crc.Value;
 2168      }
 392169    }
 2170
 2171    int FindExistingUpdate(ZipEntry entry)
 2172    {
 322173      int result = -1;
 322174      string convertedName = GetTransformedFileName(entry.Name);
 2175
 322176       if (updateIndex_.ContainsKey(convertedName)) {
 322177        result = (int)updateIndex_[convertedName];
 2178      }
 2179      /*
 2180            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2181            // for CF?
 2182            for (int index = 0; index < updates_.Count; ++index)
 2183            {
 2184              ZipUpdate zu = ( ZipUpdate )updates_[index];
 2185              if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
 2186                (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
 2187                result = index;
 2188                break;
 2189              }
 2190            }
 2191       */
 322192      return result;
 2193    }
 2194
 2195    int FindExistingUpdate(string fileName)
 2196    {
 657082197      int result = -1;
 2198
 657082199      string convertedName = GetTransformedFileName(fileName);
 2200
 657082201       if (updateIndex_.ContainsKey(convertedName)) {
 32202        result = (int)updateIndex_[convertedName];
 2203      }
 2204
 2205      /*
 2206            // This is slow like the coming of the next ice age but takes less storage and may be useful
 2207            // for CF?
 2208            for ( int index = 0; index < updates_.Count; ++index ) {
 2209              if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,
 2210                true, CultureInfo.InvariantCulture) == 0 ) {
 2211                result = index;
 2212                break;
 2213              }
 2214            }
 2215       */
 2216
 657082217      return result;
 2218    }
 2219
 2220    /// <summary>
 2221    /// Get an output stream for the specified <see cref="ZipEntry"/>
 2222    /// </summary>
 2223    /// <param name="entry">The entry to get an output stream for.</param>
 2224    /// <returns>The output stream obtained for the entry.</returns>
 2225    Stream GetOutputStream(ZipEntry entry)
 2226    {
 1682227      Stream result = baseStream_;
 2228
 1682229       if (entry.IsCrypted == true) {
 52230        result = CreateAndInitEncryptionStream(result, entry);
 2231      }
 2232
 1682233       switch (entry.CompressionMethod) {
 2234        case CompressionMethod.Stored:
 152235          result = new UncompressedStream(result);
 152236          break;
 2237
 2238        case CompressionMethod.Deflated:
 1532239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));
 1532240          dos.IsStreamOwner = false;
 1532241          result = dos;
 1532242          break;
 2243
 2244        default:
 02245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);
 2246      }
 1682247      return result;
 2248    }
 2249
 2250    void AddEntry(ZipFile workFile, ZipUpdate update)
 2251    {
 657052252      Stream source = null;
 2253
 657052254       if (update.Entry.IsFile) {
 657052255        source = update.GetSource();
 2256
 657052257         if (source == null) {
 655402258          source = updateDataSource_.GetSource(update.Entry, update.Filename);
 2259        }
 2260      }
 2261
 657052262       if (source != null) {
 1682263        using (source) {
 1682264          long sourceStreamLength = source.Length;
 1682265           if (update.OutEntry.Size < 0) {
 1652266            update.OutEntry.Size = sourceStreamLength;
 1652267          } else {
 2268            // Check for errant entries.
 32269             if (update.OutEntry.Size != sourceStreamLength) {
 02270              throw new ZipException("Entry size/stream size mismatch");
 2271            }
 2272          }
 2273
 1682274          workFile.WriteLocalEntryHeader(update);
 2275
 1682276          long dataStart = workFile.baseStream_.Position;
 2277
 1682278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 1682279            CopyBytes(update, output, source, sourceStreamLength, true);
 1682280          }
 2281
 1682282          long dataEnd = workFile.baseStream_.Position;
 1682283          update.OutEntry.CompressedSize = dataEnd - dataStart;
 2284
 1682285           if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor) {
 52286            var helper = new ZipHelperStream(workFile.baseStream_);
 52287            helper.WriteDataDescriptor(update.OutEntry);
 2288          }
 1682289        }
 2290      } else {
 655372291        workFile.WriteLocalEntryHeader(update);
 655372292        update.OutEntry.CompressedSize = 0;
 2293      }
 2294
 657052295    }
 2296
 2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)
 2298    {
 02299      workFile.WriteLocalEntryHeader(update);
 02300      long dataStart = workFile.baseStream_.Position;
 2301
 2302      // TODO: This is slow if the changes don't effect the data!!
 02303       if (update.Entry.IsFile && (update.Filename != null)) {
 02304        using (Stream output = workFile.GetOutputStream(update.OutEntry)) {
 02305          using (Stream source = this.GetInputStream(update.Entry)) {
 02306            CopyBytes(update, output, source, source.Length, true);
 02307          }
 2308        }
 2309      }
 2310
 02311      long dataEnd = workFile.baseStream_.Position;
 02312      update.Entry.CompressedSize = dataEnd - dataStart;
 02313    }
 2314
 2315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)
 2316    {
 632317      bool skipOver = false || update.Entry.Offset == destinationPosition;
 2318
 632319       if (!skipOver) {
 392320        baseStream_.Position = destinationPosition;
 392321        workFile.WriteLocalEntryHeader(update);
 392322        destinationPosition = baseStream_.Position;
 2323      }
 2324
 632325      long sourcePosition = 0;
 2326
 2327      const int NameLengthOffset = 26;
 2328
 2329      // TODO: Add base for SFX friendly handling
 632330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2331
 632332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2333
 2334      // Clumsy way of handling retrieving the original name and extra data length for now.
 2335      // TODO: Stop re-reading name and data length in CopyEntryDirect.
 632336      uint nameLength = ReadLEUshort();
 632337      uint extraLength = ReadLEUshort();
 2338
 632339      sourcePosition = baseStream_.Position + nameLength + extraLength;
 2340
 632341       if (skipOver) {
 242342         if (update.OffsetBasedSize != -1)
 222343          destinationPosition += update.OffsetBasedSize;
 2344        else
 2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar
 2346          // WinZip produces a warning on these entries:
 2347          // "caution: value of lrec.csize (compressed size) changed from ..."
 22348          destinationPosition +=
 22349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size
 22350            update.Entry.CompressedSize + GetDescriptorSize(update);
 22351      } else {
 392352         if (update.Entry.CompressedSize > 0) {
 392353          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition);
 2354        }
 392355        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
 2356      }
 392357    }
 2358
 2359    void CopyEntry(ZipFile workFile, ZipUpdate update)
 2360    {
 42361      workFile.WriteLocalEntryHeader(update);
 2362
 42363       if (update.Entry.CompressedSize > 0) {
 2364        const int NameLengthOffset = 26;
 2365
 42366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;
 2367
 2368        // TODO: This wont work for SFX files!
 42369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
 2370
 42371        uint nameLength = ReadLEUshort();
 42372        uint extraLength = ReadLEUshort();
 2373
 42374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);
 2375
 42376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
 2377      }
 42378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
 42379    }
 2380
 2381    void Reopen(Stream source)
 2382    {
 42383       if (source == null) {
 02384        throw new ZipException("Failed to reopen archive - no source");
 2385      }
 2386
 42387      isNewArchive_ = false;
 42388      baseStream_ = source;
 42389      ReadEntries();
 42390    }
 2391
 2392    void Reopen()
 2393    {
 02394       if (Name == null) {
 02395        throw new InvalidOperationException("Name is not known cannot Reopen");
 2396      }
 2397
 02398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));
 02399    }
 2400
 2401    void UpdateCommentOnly()
 2402    {
 32403      long baseLength = baseStream_.Length;
 2404
 32405      ZipHelperStream updateFile = null;
 2406
 32407       if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 12408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
 12409        updateFile = new ZipHelperStream(copyStream);
 12410        updateFile.IsStreamOwner = true;
 2411
 12412        baseStream_.Close();
 12413        baseStream_ = null;
 12414      } else {
 22415         if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 2416          // TODO: archiveStorage wasnt originally intended for this use.
 2417          // Need to revisit this to tidy up handling as archive storage currently doesnt
 2418          // handle the original stream well.
 2419          // The problem is when using an existing zip archive with an in memory archive storage.
 2420          // The open stream wont support writing but the memory storage should open the same file not an in memory one.
 2421
 2422          // Need to tidy up the archive storage interface and contract basically.
 22423          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);
 22424          updateFile = new ZipHelperStream(baseStream_);
 22425        } else {
 02426          baseStream_.Close();
 02427          baseStream_ = null;
 02428          updateFile = new ZipHelperStream(Name);
 2429        }
 2430      }
 2431
 32432      using (updateFile) {
 32433        long locatedCentralDirOffset =
 32434          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 32435                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 32436         if (locatedCentralDirOffset < 0) {
 02437          throw new ZipException("Cannot find central directory");
 2438        }
 2439
 2440        const int CentralHeaderCommentSizeOffset = 16;
 32441        updateFile.Position += CentralHeaderCommentSizeOffset;
 2442
 32443        byte[] rawComment = newComment_.RawComment;
 2444
 32445        updateFile.WriteLEShort(rawComment.Length);
 32446        updateFile.Write(rawComment, 0, rawComment.Length);
 32447        updateFile.SetLength(updateFile.Position);
 32448      }
 2449
 32450       if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {
 12451        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 12452      } else {
 22453        ReadEntries();
 2454      }
 22455    }
 2456
 2457    /// <summary>
 2458    /// Class used to sort updates.
 2459    /// </summary>
 2460    class UpdateComparer : IComparer
 2461    {
 2462      /// <summary>
 2463      /// Compares two objects and returns a value indicating whether one is
 2464      /// less than, equal to or greater than the other.
 2465      /// </summary>
 2466      /// <param name="x">First object to compare</param>
 2467      /// <param name="y">Second object to compare.</param>
 2468      /// <returns>Compare result.</returns>
 2469      public int Compare(
 2470        object x,
 2471        object y)
 2472      {
 4712473        var zx = x as ZipUpdate;
 4712474        var zy = y as ZipUpdate;
 2475
 2476        int result;
 2477
 4712478         if (zx == null) {
 502479           if (zy == null) {
 102480            result = 0;
 102481          } else {
 402482            result = -1;
 2483          }
 4612484         } else if (zy == null) {
 112485          result = 1;
 112486        } else {
 4102487           int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;
 4102488           int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;
 2489
 4102490          result = xCmdValue - yCmdValue;
 4102491           if (result == 0) {
 3782492            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;
 3782493             if (offsetDiff < 0) {
 162494              result = -1;
 3782495             } else if (offsetDiff == 0) {
 2552496              result = 0;
 2552497            } else {
 1072498              result = 1;
 2499            }
 2500          }
 2501        }
 4712502        return result;
 2503      }
 2504    }
 2505
 2506    void RunUpdates()
 2507    {
 442508      long sizeEntries = 0;
 442509      long endOfStream = 0;
 442510      bool directUpdate = false;
 442511      long destinationPosition = 0; // NOT SFX friendly
 2512
 2513      ZipFile workFile;
 2514
 442515       if (IsNewArchive) {
 162516        workFile = this;
 162517        workFile.baseStream_.Position = 0;
 162518        directUpdate = true;
 442519       } else if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
 252520        workFile = this;
 252521        workFile.baseStream_.Position = 0;
 252522        directUpdate = true;
 2523
 2524        // Sort the updates by offset within copies/modifies, then adds.
 2525        // This ensures that data required by copies will not be overwritten.
 252526        updates_.Sort(new UpdateComparer());
 252527      } else {
 32528        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
 32529        workFile.UseZip64 = UseZip64;
 2530
 32531         if (key != null) {
 12532          workFile.key = (byte[])key.Clone();
 2533        }
 2534      }
 2535
 2536      try {
 1317022537        foreach (ZipUpdate update in updates_) {
 658072538           if (update != null) {
 657722539             switch (update.Command) {
 2540              case UpdateCommand.Copy:
 672541                 if (directUpdate) {
 632542                  CopyEntryDirect(workFile, update, ref destinationPosition);
 632543                } else {
 42544                  CopyEntry(workFile, update);
 2545                }
 42546                break;
 2547
 2548              case UpdateCommand.Modify:
 2549                // TODO: Direct modifying of an entry will take some legwork.
 02550                ModifyEntry(workFile, update);
 02551                break;
 2552
 2553              case UpdateCommand.Add:
 657052554                 if (!IsNewArchive && directUpdate) {
 1342555                  workFile.baseStream_.Position = destinationPosition;
 2556                }
 2557
 657052558                AddEntry(workFile, update);
 2559
 657052560                 if (directUpdate) {
 657042561                  destinationPosition = workFile.baseStream_.Position;
 2562                }
 2563                break;
 2564            }
 2565          }
 2566        }
 2567
 442568         if (!IsNewArchive && directUpdate) {
 252569          workFile.baseStream_.Position = destinationPosition;
 2570        }
 2571
 442572        long centralDirOffset = workFile.baseStream_.Position;
 2573
 1317022574        foreach (ZipUpdate update in updates_) {
 658072575           if (update != null) {
 657722576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
 2577          }
 2578        }
 2579
 442580        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
 442581        using (ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_)) {
 442582          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);
 442583        }
 2584
 442585        endOfStream = workFile.baseStream_.Position;
 2586
 2587        // And now patch entries...
 1317022588        foreach (ZipUpdate update in updates_) {
 658072589           if (update != null) {
 2590            // If the size of the entry is zero leave the crc as 0 as well.
 2591            // The calculated crc will be all bits on...
 657722592             if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {
 1682593              workFile.baseStream_.Position = update.CrcPatchOffset;
 1682594              workFile.WriteLEInt((int)update.OutEntry.Crc);
 2595            }
 2596
 657722597             if (update.SizePatchOffset > 0) {
 1682598              workFile.baseStream_.Position = update.SizePatchOffset;
 1682599               if (update.OutEntry.LocalHeaderRequiresZip64) {
 22600                workFile.WriteLeLong(update.OutEntry.Size);
 22601                workFile.WriteLeLong(update.OutEntry.CompressedSize);
 22602              } else {
 1662603                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);
 1662604                workFile.WriteLEInt((int)update.OutEntry.Size);
 2605              }
 2606            }
 2607          }
 2608        }
 442609      } catch {
 02610        workFile.Close();
 02611         if (!directUpdate && (workFile.Name != null)) {
 02612          File.Delete(workFile.Name);
 2613        }
 02614        throw;
 2615      }
 2616
 442617       if (directUpdate) {
 412618        workFile.baseStream_.SetLength(endOfStream);
 412619        workFile.baseStream_.Flush();
 412620        isNewArchive_ = false;
 412621        ReadEntries();
 412622      } else {
 32623        baseStream_.Close();
 32624        Reopen(archiveStorage_.ConvertTemporaryToFinal());
 2625      }
 32626    }
 2627
 2628    void CheckUpdating()
 2629    {
 657912630       if (updates_ == null) {
 02631        throw new InvalidOperationException("BeginUpdate has not been called");
 2632      }
 657912633    }
 2634
 2635    #endregion
 2636
 2637    #region ZipUpdate class
 2638    /// <summary>
 2639    /// Represents a pending update to a Zip file.
 2640    /// </summary>
 2641    class ZipUpdate
 2642    {
 2643      #region Constructors
 32644      public ZipUpdate(string fileName, ZipEntry entry)
 2645      {
 32646        command_ = UpdateCommand.Add;
 32647        entry_ = entry;
 32648        filename_ = fileName;
 32649      }
 2650
 2651      [Obsolete]
 02652      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 2653      {
 02654        command_ = UpdateCommand.Add;
 02655        entry_ = new ZipEntry(entryName);
 02656        entry_.CompressionMethod = compressionMethod;
 02657        filename_ = fileName;
 02658      }
 2659
 2660      [Obsolete]
 2661      public ZipUpdate(string fileName, string entryName)
 02662        : this(fileName, entryName, CompressionMethod.Deflated)
 2663      {
 2664        // Do nothing.
 02665      }
 2666
 2667      [Obsolete]
 02668      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 2669      {
 02670        command_ = UpdateCommand.Add;
 02671        entry_ = new ZipEntry(entryName);
 02672        entry_.CompressionMethod = compressionMethod;
 02673        dataSource_ = dataSource;
 02674      }
 2675
 1652676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 2677      {
 1652678        command_ = UpdateCommand.Add;
 1652679        entry_ = entry;
 1652680        dataSource_ = dataSource;
 1652681      }
 2682
 02683      public ZipUpdate(ZipEntry original, ZipEntry updated)
 2684      {
 02685        throw new ZipException("Modify not currently supported");
 2686        /*
 2687          command_ = UpdateCommand.Modify;
 2688          entry_ = ( ZipEntry )original.Clone();
 2689          outEntry_ = ( ZipEntry )updated.Clone();
 2690        */
 2691      }
 2692
 656482693      public ZipUpdate(UpdateCommand command, ZipEntry entry)
 2694      {
 656482695        command_ = command;
 656482696        entry_ = (ZipEntry)entry.Clone();
 656482697      }
 2698
 2699
 2700      /// <summary>
 2701      /// Copy an existing entry.
 2702      /// </summary>
 2703      /// <param name="entry">The existing entry to copy.</param>
 2704      public ZipUpdate(ZipEntry entry)
 1112705        : this(UpdateCommand.Copy, entry)
 2706      {
 2707        // Do nothing.
 1112708      }
 2709      #endregion
 2710
 2711      /// <summary>
 2712      /// Get the <see cref="ZipEntry"/> for this update.
 2713      /// </summary>
 2714      /// <remarks>This is the source or original entry.</remarks>
 2715      public ZipEntry Entry {
 2638342716        get { return entry_; }
 2717      }
 2718
 2719      /// <summary>
 2720      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.
 2721      /// </summary>
 2722      public ZipEntry OutEntry {
 2723        get {
 1989102724           if (outEntry_ == null) {
 657722725            outEntry_ = (ZipEntry)entry_.Clone();
 2726          }
 2727
 1989102728          return outEntry_;
 2729        }
 2730      }
 2731
 2732      /// <summary>
 2733      /// Get the command for this update.
 2734      /// </summary>
 2735      public UpdateCommand Command {
 1328822736        get { return command_; }
 2737      }
 2738
 2739      /// <summary>
 2740      /// Get the filename if any for this update.  Null if none exists.
 2741      /// </summary>
 2742      public string Filename {
 655402743        get { return filename_; }
 2744      }
 2745
 2746      /// <summary>
 2747      /// Get/set the location of the size patch for this update.
 2748      /// </summary>
 2749      public long SizePatchOffset {
 659402750        get { return sizePatchOffset_; }
 3362751        set { sizePatchOffset_ = value; }
 2752      }
 2753
 2754      /// <summary>
 2755      /// Get /set the location of the crc patch for this update.
 2756      /// </summary>
 2757      public long CrcPatchOffset {
 659402758        get { return crcPatchOffset_; }
 3362759        set { crcPatchOffset_ = value; }
 2760      }
 2761
 2762      /// <summary>
 2763      /// Get/set the size calculated by offset.
 2764      /// Specifically, the difference between this and next entry's starting offset.
 2765      /// </summary>
 2766      public long OffsetBasedSize {
 462767        get { return _offsetBasedSize; }
 1602768        set { _offsetBasedSize = value; }
 2769      }
 2770
 2771      public Stream GetSource()
 2772      {
 657052773        Stream result = null;
 657052774         if (dataSource_ != null) {
 1652775          result = dataSource_.GetSource();
 2776        }
 2777
 657052778        return result;
 2779      }
 2780
 2781      #region Instance Fields
 2782      ZipEntry entry_;
 2783      ZipEntry outEntry_;
 2784      UpdateCommand command_;
 2785      IStaticDataSource dataSource_;
 2786      string filename_;
 658162787      long sizePatchOffset_ = -1;
 658162788      long crcPatchOffset_ = -1;
 658162789      long _offsetBasedSize = -1;
 2790      #endregion
 2791    }
 2792
 2793    #endregion
 2794    #endregion
 2795
 2796    #region Disposing
 2797
 2798    #region IDisposable Members
 2799    void IDisposable.Dispose()
 2800    {
 822801      Close();
 822802    }
 2803    #endregion
 2804
 2805    void DisposeInternal(bool disposing)
 2806    {
 982807       if (!isDisposed_) {
 882808        isDisposed_ = true;
 882809        entries_ = new ZipEntry[0];
 2810
 882811         if (IsStreamOwner && (baseStream_ != null)) {
 492812          lock (baseStream_) {
 492813            baseStream_.Close();
 492814          }
 2815        }
 2816
 882817        PostUpdateCleanup();
 2818      }
 982819    }
 2820
 2821    /// <summary>
 2822    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.
 2823    /// </summary>
 2824    /// <param name="disposing">true to release both managed and unmanaged resources;
 2825    /// false to release only unmanaged resources.</param>
 2826    protected virtual void Dispose(bool disposing)
 2827    {
 62828      DisposeInternal(disposing);
 62829    }
 2830
 2831    #endregion
 2832
 2833    #region Internal routines
 2834    #region Reading
 2835    /// <summary>
 2836    /// Read an unsigned short in little endian byte order.
 2837    /// </summary>
 2838    /// <returns>Returns the value read.</returns>
 2839    /// <exception cref="EndOfStreamException">
 2840    /// The stream ends prematurely
 2841    /// </exception>
 2842    ushort ReadLEUshort()
 2843    {
 34961052844      int data1 = baseStream_.ReadByte();
 2845
 34961052846       if (data1 < 0) {
 02847        throw new EndOfStreamException("End of stream");
 2848      }
 2849
 34961052850      int data2 = baseStream_.ReadByte();
 2851
 34961052852       if (data2 < 0) {
 02853        throw new EndOfStreamException("End of stream");
 2854      }
 2855
 2856
 34961052857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));
 2858    }
 2859
 2860    /// <summary>
 2861    /// Read a uint in little endian byte order.
 2862    /// </summary>
 2863    /// <returns>Returns the value read.</returns>
 2864    /// <exception cref="IOException">
 2865    /// An i/o error occurs.
 2866    /// </exception>
 2867    /// <exception cref="System.IO.EndOfStreamException">
 2868    /// The file ends prematurely
 2869    /// </exception>
 2870    uint ReadLEUint()
 2871    {
 9893832872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));
 2873    }
 2874
 2875    ulong ReadLEUlong()
 2876    {
 62877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);
 2878    }
 2879
 2880    #endregion
 2881    // NOTE this returns the offset of the first byte after the signature.
 2882    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 2883    {
 1152884      using (ZipHelperStream les = new ZipHelperStream(baseStream_)) {
 1152885        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
 2886      }
 1152887    }
 2888
 2889    /// <summary>
 2890    /// Search for and read the central directory of a zip file filling the entries array.
 2891    /// </summary>
 2892    /// <exception cref="System.IO.IOException">
 2893    /// An i/o error occurs.
 2894    /// </exception>
 2895    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 2896    /// The central directory is malformed or cannot be found
 2897    /// </exception>
 2898    void ReadEntries()
 2899    {
 2900      // Search for the End Of Central Directory.  When a zip comment is
 2901      // present the directory will start earlier
 2902      //
 2903      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
 2904      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
 2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
 2906      // this could be invalid.
 2907      // Could also speed this up by reading memory in larger blocks.
 2908
 1142909       if (baseStream_.CanSeek == false) {
 02910        throw new ZipException("ZipFile stream must be seekable");
 2911      }
 2912
 1142913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
 1142914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
 2915
 1142916       if (locatedEndOfCentralDir < 0) {
 12917        throw new ZipException("Cannot find central directory");
 2918      }
 2919
 2920      // Read end of central directory record
 1132921      ushort thisDiskNumber = ReadLEUshort();
 1132922      ushort startCentralDirDisk = ReadLEUshort();
 1132923      ulong entriesForThisDisk = ReadLEUshort();
 1132924      ulong entriesForWholeCentralDir = ReadLEUshort();
 1132925      ulong centralDirSize = ReadLEUint();
 1132926      long offsetOfCentralDir = ReadLEUint();
 1132927      uint commentSize = ReadLEUshort();
 2928
 1132929       if (commentSize > 0) {
 102930        byte[] comment = new byte[commentSize];
 2931
 102932        StreamUtils.ReadFully(baseStream_, comment);
 102933        comment_ = ZipConstants.ConvertToString(comment);
 102934      } else {
 1032935        comment_ = string.Empty;
 2936      }
 2937
 1132938      bool isZip64 = false;
 2939
 2940      // Check if zip64 header information is required.
 1132941       if ((thisDiskNumber == 0xffff) ||
 1132942        (startCentralDirDisk == 0xffff) ||
 1132943        (entriesForThisDisk == 0xffff) ||
 1132944        (entriesForWholeCentralDir == 0xffff) ||
 1132945        (centralDirSize == 0xffffffff) ||
 1132946        (offsetOfCentralDir == 0xffffffff)) {
 12947        isZip64 = true;
 2948
 12949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 
 12950         if (offset < 0) {
 02951          throw new ZipException("Cannot find Zip64 locator");
 2952        }
 2953
 2954        // number of the disk with the start of the zip64 end of central directory 4 bytes
 2955        // relative offset of the zip64 end of central directory record 8 bytes
 2956        // total number of disks 4 bytes
 12957        ReadLEUint(); // startDisk64 is not currently used
 12958        ulong offset64 = ReadLEUlong();
 12959        uint totalDisks = ReadLEUint();
 2960
 12961        baseStream_.Position = (long)offset64;
 12962        long sig64 = ReadLEUint();
 2963
 12964         if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {
 02965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
 2966        }
 2967
 2968        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
 12969        ulong recordSize = ReadLEUlong();
 12970        int versionMadeBy = ReadLEUshort();
 12971        int versionToExtract = ReadLEUshort();
 12972        uint thisDisk = ReadLEUint();
 12973        uint centralDirDisk = ReadLEUint();
 12974        entriesForThisDisk = ReadLEUlong();
 12975        entriesForWholeCentralDir = ReadLEUlong();
 12976        centralDirSize = ReadLEUlong();
 12977        offsetOfCentralDir = (long)ReadLEUlong();
 2978
 2979        // NOTE: zip64 extensible data sector (variable size) is ignored.
 2980      }
 2981
 1132982      entries_ = new ZipEntry[entriesForThisDisk];
 2983
 2984      // SFX/embedded support, find the offset of the first entry vis the start of the stream
 2985      // This applies to Zip files that are appended to the end of an SFX stub.
 2986      // Or are appended as a resource to an executable.
 2987      // Zip files created by some archivers have the offsets altered to reflect the true offsets
 2988      // and so dont require any adjustment here...
 2989      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
 1132990       if (!isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize))) {
 22991        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
 22992         if (offsetOfFirstEntry <= 0) {
 02993          throw new ZipException("Invalid embedded zip archive");
 2994        }
 2995      }
 2996
 1132997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
 2998
 1321382999       for (ulong i = 0; i < entriesForThisDisk; i++) {
 659563000         if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
 03001          throw new ZipException("Wrong Central Directory signature");
 3002        }
 3003
 659563004        int versionMadeBy = ReadLEUshort();
 659563005        int versionToExtract = ReadLEUshort();
 659563006        int bitFlags = ReadLEUshort();
 659563007        int method = ReadLEUshort();
 659563008        uint dostime = ReadLEUint();
 659563009        uint crc = ReadLEUint();
 659563010        var csize = (long)ReadLEUint();
 659563011        var size = (long)ReadLEUint();
 659563012        int nameLen = ReadLEUshort();
 659563013        int extraLen = ReadLEUshort();
 659563014        int commentLen = ReadLEUshort();
 3015
 659563016        int diskStartNo = ReadLEUshort();  // Not currently used
 659563017        int internalAttributes = ReadLEUshort();  // Not currently used
 3018
 659563019        uint externalAttributes = ReadLEUint();
 659563020        long offset = ReadLEUint();
 3021
 659563022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
 3023
 659563024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
 659563025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);
 3026
 659563027        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
 659563028        entry.Crc = crc & 0xffffffffL;
 659563029        entry.Size = size & 0xffffffffL;
 659563030        entry.CompressedSize = csize & 0xffffffffL;
 659563031        entry.Flags = bitFlags;
 659563032        entry.DosTime = (uint)dostime;
 659563033        entry.ZipFileIndex = (long)i;
 659563034        entry.Offset = offset;
 659563035        entry.ExternalFileAttributes = (int)externalAttributes;
 3036
 659563037         if ((bitFlags & 8) == 0) {
 659373038          entry.CryptoCheckValue = (byte)(crc >> 24);
 659373039        } else {
 193040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
 3041        }
 3042
 659563043         if (extraLen > 0) {
 453044          byte[] extra = new byte[extraLen];
 453045          StreamUtils.ReadFully(baseStream_, extra);
 453046          entry.ExtraData = extra;
 3047        }
 3048
 659563049        entry.ProcessExtraData(false);
 3050
 659563051         if (commentLen > 0) {
 03052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
 03053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
 3054        }
 3055
 659563056        entries_[i] = entry;
 3057      }
 1133058    }
 3059
 3060    /// <summary>
 3061    /// Locate the data for a given entry.
 3062    /// </summary>
 3063    /// <returns>
 3064    /// The start offset of the data.
 3065    /// </returns>
 3066    /// <exception cref="System.IO.EndOfStreamException">
 3067    /// The stream ends prematurely
 3068    /// </exception>
 3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
 3070    /// The local header signature is invalid, the entry and central header file name lengths are different
 3071    /// or the local and entry compression methods dont match
 3072    /// </exception>
 3073    long LocateEntry(ZipEntry entry)
 3074    {
 659463075      return TestLocalHeader(entry, HeaderTest.Extract);
 3076    }
 3077
 3078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
 3079    {
 103080      CryptoStream result = null;
 3081
 103082       if ((entry.Version < ZipConstants.VersionStrongEncryption)
 103083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 103084        var classicManaged = new PkzipClassicManaged();
 3085
 103086        OnKeysRequired(entry.Name);
 103087         if (HaveKeys == false) {
 03088          throw new ZipException("No password available for encrypted stream");
 3089        }
 3090
 103091        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
 103092        CheckClassicPassword(result, entry);
 103093      } else {
 03094         if (entry.Version == ZipConstants.VERSION_AES) {
 3095          //
 03096          OnKeysRequired(entry.Name);
 03097           if (HaveKeys == false) {
 03098            throw new ZipException("No password available for AES encrypted stream");
 3099          }
 03100          int saltLen = entry.AESSaltLen;
 03101          byte[] saltBytes = new byte[saltLen];
 03102          int saltIn = baseStream.Read(saltBytes, 0, saltLen);
 03103           if (saltIn != saltLen)
 03104            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
 3105          //
 03106          byte[] pwdVerifyRead = new byte[2];
 03107          baseStream.Read(pwdVerifyRead, 0, 2);
 03108          int blockSize = entry.AESKeySize / 8;   // bits to bytes
 3109
 03110          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
 03111          byte[] pwdVerifyCalc = decryptor.PwdVerifier;
 03112           if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
 03113            throw new ZipException("Invalid password for AES");
 03114          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
 03115        } else {
 03116          throw new ZipException("Decryption method not supported");
 3117        }
 3118      }
 3119
 103120      return result;
 3121    }
 3122
 3123    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
 3124    {
 53125      CryptoStream result = null;
 53126       if ((entry.Version < ZipConstants.VersionStrongEncryption)
 53127        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
 53128        var classicManaged = new PkzipClassicManaged();
 3129
 53130        OnKeysRequired(entry.Name);
 53131         if (HaveKeys == false) {
 03132          throw new ZipException("No password available for encrypted stream");
 3133        }
 3134
 3135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
 3136        // which doesnt do this.
 53137        result = new CryptoStream(new UncompressedStream(baseStream),
 53138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
 3139
 53140         if ((entry.Crc < 0) || (entry.Flags & 8) != 0) {
 53141          WriteEncryptionHeader(result, entry.DosTime << 16);
 53142        } else {
 03143          WriteEncryptionHeader(result, entry.Crc);
 3144        }
 3145      }
 53146      return result;
 3147    }
 3148
 3149    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
 3150    {
 103151      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
 103152      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
 103153       if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
 03154        throw new ZipException("Invalid password");
 3155      }
 103156    }
 3157
 3158    static void WriteEncryptionHeader(Stream stream, long crcValue)
 3159    {
 53160      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
 53161      var rnd = new Random();
 53162      rnd.NextBytes(cryptBuffer);
 53163      cryptBuffer[11] = (byte)(crcValue >> 24);
 53164      stream.Write(cryptBuffer, 0, cryptBuffer.Length);
 53165    }
 3166
 3167    #endregion
 3168
 3169    #region Instance Fields
 3170    bool isDisposed_;
 3171    string name_;
 3172    string comment_;
 3173    string rawPassword_;
 3174    Stream baseStream_;
 3175    bool isStreamOwner;
 3176    long offsetOfFirstEntry;
 3177    ZipEntry[] entries_;
 3178    byte[] key;
 3179    bool isNewArchive_;
 3180
 3181    // Default is dynamic which is not backwards compatible and can cause problems
 3182    // with XP's built in compression which cant read Zip64 archives.
 3183    // However it does avoid the situation were a large file is added and cannot be completed correctly.
 3184    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.
 883185    UseZip64 useZip64_ = UseZip64.Dynamic;
 3186
 3187    #region Zip Update Instance Fields
 3188    ArrayList updates_;
 3189    long updateCount_; // Count is managed manually as updates_ can contain nulls!
 3190    Hashtable updateIndex_;
 3191    IArchiveStorage archiveStorage_;
 3192    IDynamicDataSource updateDataSource_;
 3193    bool contentsEdited_;
 883194    int bufferSize_ = DefaultBufferSize;
 3195    byte[] copyBuffer_;
 3196    ZipString newComment_;
 3197    bool commentEdited_;
 883198    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();
 3199    #endregion
 3200    #endregion
 3201
 3202    #region Support Classes
 3203    /// <summary>
 3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.
 3205    /// </summary>
 3206    class ZipString
 3207    {
 3208      #region Constructors
 3209      /// <summary>
 3210      /// Initialise a <see cref="ZipString"/> with a string.
 3211      /// </summary>
 3212      /// <param name="comment">The textual string form.</param>
 33213      public ZipString(string comment)
 3214      {
 33215        comment_ = comment;
 33216        isSourceString_ = true;
 33217      }
 3218
 3219      /// <summary>
 3220      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.
 3221      /// </summary>
 3222      /// <param name="rawString"></param>
 03223      public ZipString(byte[] rawString)
 3224      {
 03225        rawComment_ = rawString;
 03226      }
 3227      #endregion
 3228
 3229      /// <summary>
 3230      /// Get a value indicating the original source of data for this instance.
 3231      /// True if the source was a string; false if the source was binary data.
 3232      /// </summary>
 3233      public bool IsSourceString {
 03234        get { return isSourceString_; }
 3235      }
 3236
 3237      /// <summary>
 3238      /// Get the length of the comment when represented as raw bytes.
 3239      /// </summary>
 3240      public int RawLength {
 3241        get {
 33242          MakeBytesAvailable();
 33243          return rawComment_.Length;
 3244        }
 3245      }
 3246
 3247      /// <summary>
 3248      /// Get the comment in its 'raw' form as plain bytes.
 3249      /// </summary>
 3250      public byte[] RawComment {
 3251        get {
 33252          MakeBytesAvailable();
 33253          return (byte[])rawComment_.Clone();
 3254        }
 3255      }
 3256
 3257      /// <summary>
 3258      /// Reset the comment to its initial state.
 3259      /// </summary>
 3260      public void Reset()
 3261      {
 03262         if (isSourceString_) {
 03263          rawComment_ = null;
 03264        } else {
 03265          comment_ = null;
 3266        }
 03267      }
 3268
 3269      void MakeTextAvailable()
 3270      {
 03271         if (comment_ == null) {
 03272          comment_ = ZipConstants.ConvertToString(rawComment_);
 3273        }
 03274      }
 3275
 3276      void MakeBytesAvailable()
 3277      {
 63278         if (rawComment_ == null) {
 33279          rawComment_ = ZipConstants.ConvertToArray(comment_);
 3280        }
 63281      }
 3282
 3283      /// <summary>
 3284      /// Implicit conversion of comment to a string.
 3285      /// </summary>
 3286      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>
 3287      /// <returns>The textual equivalent for the input value.</returns>
 3288      static public implicit operator string(ZipString zipString)
 3289      {
 03290        zipString.MakeTextAvailable();
 03291        return zipString.comment_;
 3292      }
 3293
 3294      #region Instance Fields
 3295      string comment_;
 3296      byte[] rawComment_;
 3297      bool isSourceString_;
 3298      #endregion
 3299    }
 3300
 3301    /// <summary>
 3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>
 3303    /// </summary>
 3304    class ZipEntryEnumerator : IEnumerator
 3305    {
 3306      #region Constructors
 43307      public ZipEntryEnumerator(ZipEntry[] entries)
 3308      {
 43309        array = entries;
 43310      }
 3311
 3312      #endregion
 3313      #region IEnumerator Members
 3314      public object Current {
 3315        get {
 223316          return array[index];
 3317        }
 3318      }
 3319
 3320      public void Reset()
 3321      {
 03322        index = -1;
 03323      }
 3324
 3325      public bool MoveNext()
 3326      {
 263327        return (++index < array.Length);
 3328      }
 3329      #endregion
 3330      #region Instance Fields
 3331      ZipEntry[] array;
 43332      int index = -1;
 3333      #endregion
 3334    }
 3335
 3336    /// <summary>
 3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data
 3338    /// to and flush, but cannot read, seek or do anything else to.
 3339    /// </summary>
 3340    class UncompressedStream : Stream
 3341    {
 3342      #region Constructors
 203343      public UncompressedStream(Stream baseStream)
 3344      {
 203345        baseStream_ = baseStream;
 203346      }
 3347
 3348      #endregion
 3349
 3350      /// <summary>
 3351      /// Close this stream instance.
 3352      /// </summary>
 3353      public override void Close()
 3354      {
 3355        // Do nothing
 153356      }
 3357
 3358      /// <summary>
 3359      /// Gets a value indicating whether the current stream supports reading.
 3360      /// </summary>
 3361      public override bool CanRead {
 3362        get {
 03363          return false;
 3364        }
 3365      }
 3366
 3367      /// <summary>
 3368      /// Write any buffered data to underlying storage.
 3369      /// </summary>
 3370      public override void Flush()
 3371      {
 03372        baseStream_.Flush();
 03373      }
 3374
 3375      /// <summary>
 3376      /// Gets a value indicating whether the current stream supports writing.
 3377      /// </summary>
 3378      public override bool CanWrite {
 3379        get {
 53380          return baseStream_.CanWrite;
 3381        }
 3382      }
 3383
 3384      /// <summary>
 3385      /// Gets a value indicating whether the current stream supports seeking.
 3386      /// </summary>
 3387      public override bool CanSeek {
 3388        get {
 03389          return false;
 3390        }
 3391      }
 3392
 3393      /// <summary>
 3394      /// Get the length in bytes of the stream.
 3395      /// </summary>
 3396      public override long Length {
 3397        get {
 03398          return 0;
 3399        }
 3400      }
 3401
 3402      /// <summary>
 3403      /// Gets or sets the position within the current stream.
 3404      /// </summary>
 3405      public override long Position {
 3406        get {
 03407          return baseStream_.Position;
 3408        }
 3409        set {
 03410          throw new NotImplementedException();
 3411        }
 3412      }
 3413
 3414      /// <summary>
 3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3416      /// </summary>
 3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3419      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3420      /// <returns>
 3421      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3422      /// </returns>
 3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3425      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3426      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3427      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3428      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3429      public override int Read(byte[] buffer, int offset, int count)
 3430      {
 03431        return 0;
 3432      }
 3433
 3434      /// <summary>
 3435      /// Sets the position within the current stream.
 3436      /// </summary>
 3437      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3438      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3439      /// <returns>
 3440      /// The new position within the current stream.
 3441      /// </returns>
 3442      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3443      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3445      public override long Seek(long offset, SeekOrigin origin)
 3446      {
 03447        return 0;
 3448      }
 3449
 3450      /// <summary>
 3451      /// Sets the length of the current stream.
 3452      /// </summary>
 3453      /// <param name="value">The desired length of the current stream in bytes.</param>
 3454      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3455      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3456      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3457      public override void SetLength(long value)
 3458      {
 03459      }
 3460
 3461      /// <summary>
 3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3463      /// </summary>
 3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3466      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3467      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3468      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3469      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3470      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3471      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3472      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3473      public override void Write(byte[] buffer, int offset, int count)
 3474      {
 253475        baseStream_.Write(buffer, offset, count);
 253476      }
 3477
 3478      readonly
 3479
 3480      #region Instance Fields
 3481      Stream baseStream_;
 3482      #endregion
 3483    }
 3484
 3485    /// <summary>
 3486    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>
 3487    /// whose data is only a part or subsection of a file.
 3488    /// </summary>
 3489    class PartialInputStream : Stream
 3490    {
 3491      #region Constructors
 3492      /// <summary>
 3493      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.
 3494      /// </summary>
 3495      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>
 3496      /// <param name="start">The start of the partial data.</param>
 3497      /// <param name="length">The length of the partial data.</param>
 659463498      public PartialInputStream(ZipFile zipFile, long start, long length)
 3499      {
 659463500        start_ = start;
 659463501        length_ = length;
 3502
 3503        // Although this is the only time the zipfile is used
 3504        // keeping a reference here prevents premature closure of
 3505        // this zip file and thus the baseStream_.
 3506
 3507        // Code like this will cause apparently random failures depending
 3508        // on the size of the files and when garbage is collected.
 3509        //
 3510        // ZipFile z = new ZipFile (stream);
 3511        // Stream reader = z.GetInputStream(0);
 3512        // uses reader here....
 659463513        zipFile_ = zipFile;
 659463514        baseStream_ = zipFile_.baseStream_;
 659463515        readPos_ = start;
 659463516        end_ = start + length;
 659463517      }
 3518      #endregion
 3519
 3520      /// <summary>
 3521      /// Read a byte from this stream.
 3522      /// </summary>
 3523      /// <returns>Returns the byte read or -1 on end of stream.</returns>
 3524      public override int ReadByte()
 3525      {
 1583526         if (readPos_ >= end_) {
 3527          // -1 is the correct value at end of stream.
 03528          return -1;
 3529        }
 3530
 1583531        lock (baseStream_) {
 1583532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);
 1583533          return baseStream_.ReadByte();
 3534        }
 1583535      }
 3536
 3537      /// <summary>
 3538      /// Close this <see cref="PartialInputStream">partial input stream</see>.
 3539      /// </summary>
 3540      /// <remarks>
 3541      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.
 3542      /// </remarks>
 3543      public override void Close()
 3544      {
 3545        // Do nothing at all!
 659183546      }
 3547
 3548      /// <summary>
 3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of
 3550      /// </summary>
 3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array
 3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur
 3553      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
 3554      /// <returns>
 3555      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma
 3556      /// </returns>
 3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e
 3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3559      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
 3560      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3561      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3562      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3563      public override int Read(byte[] buffer, int offset, int count)
 3564      {
 663793565        lock (baseStream_) {
 663793566           if (count > end_ - readPos_) {
 663483567            count = (int)(end_ - readPos_);
 663483568             if (count == 0) {
 659433569              return 0;
 3570            }
 3571          }
 3572          // Protect against Stream implementations that throw away their buffer on every Seek
 3573          // (for example, Mono FileStream)
 4363574           if (baseStream_.Position != readPos_) {
 03575            baseStream_.Seek(readPos_, SeekOrigin.Begin);
 3576          }
 4363577          int readCount = baseStream_.Read(buffer, offset, count);
 4363578           if (readCount > 0) {
 4363579            readPos_ += readCount;
 3580          }
 4363581          return readCount;
 3582        }
 663793583      }
 3584
 3585      /// <summary>
 3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n
 3587      /// </summary>
 3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par
 3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea
 3590      /// <param name="count">The number of bytes to be written to the current stream.</param>
 3591      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3592      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
 3593      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3594      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
 3595      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </
 3596      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
 3597      public override void Write(byte[] buffer, int offset, int count)
 3598      {
 03599        throw new NotSupportedException();
 3600      }
 3601
 3602      /// <summary>
 3603      /// When overridden in a derived class, sets the length of the current stream.
 3604      /// </summary>
 3605      /// <param name="value">The desired length of the current stream in bytes.</param>
 3606      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as
 3607      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3608      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3609      public override void SetLength(long value)
 3610      {
 03611        throw new NotSupportedException();
 3612      }
 3613
 3614      /// <summary>
 3615      /// When overridden in a derived class, sets the position within the current stream.
 3616      /// </summary>
 3617      /// <param name="offset">A byte offset relative to the origin parameter.</param>
 3618      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 
 3619      /// <returns>
 3620      /// The new position within the current stream.
 3621      /// </returns>
 3622      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3623      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is
 3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3625      public override long Seek(long offset, SeekOrigin origin)
 3626      {
 53627        long newPos = readPos_;
 3628
 53629         switch (origin) {
 3630          case SeekOrigin.Begin:
 53631            newPos = start_ + offset;
 53632            break;
 3633
 3634          case SeekOrigin.Current:
 03635            newPos = readPos_ + offset;
 03636            break;
 3637
 3638          case SeekOrigin.End:
 03639            newPos = end_ + offset;
 3640            break;
 3641        }
 3642
 53643         if (newPos < start_) {
 03644          throw new ArgumentException("Negative position is invalid");
 3645        }
 3646
 53647         if (newPos >= end_) {
 03648          throw new IOException("Cannot seek past end");
 3649        }
 53650        readPos_ = newPos;
 53651        return readPos_;
 3652      }
 3653
 3654      /// <summary>
 3655      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
 3656      /// </summary>
 3657      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3658      public override void Flush()
 3659      {
 3660        // Nothing to do.
 03661      }
 3662
 3663      /// <summary>
 3664      /// Gets or sets the position within the current stream.
 3665      /// </summary>
 3666      /// <value></value>
 3667      /// <returns>The current position within the stream.</returns>
 3668      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
 3669      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>
 3670      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3671      public override long Position {
 33672        get { return readPos_ - start_; }
 3673        set {
 03674          long newPos = start_ + value;
 3675
 03676           if (newPos < start_) {
 03677            throw new ArgumentException("Negative position is invalid");
 3678          }
 3679
 03680           if (newPos >= end_) {
 03681            throw new InvalidOperationException("Cannot seek past end");
 3682          }
 03683          readPos_ = newPos;
 03684        }
 3685      }
 3686
 3687      /// <summary>
 3688      /// Gets the length in bytes of the stream.
 3689      /// </summary>
 3690      /// <value></value>
 3691      /// <returns>A long value representing the length of the stream in bytes.</returns>
 3692      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep
 3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio
 3694      public override long Length {
 23695        get { return length_; }
 3696      }
 3697
 3698      /// <summary>
 3699      /// Gets a value indicating whether the current stream supports writing.
 3700      /// </summary>
 3701      /// <value>false</value>
 3702      /// <returns>true if the stream supports writing; otherwise, false.</returns>
 3703      public override bool CanWrite {
 03704        get { return false; }
 3705      }
 3706
 3707      /// <summary>
 3708      /// Gets a value indicating whether the current stream supports seeking.
 3709      /// </summary>
 3710      /// <value>true</value>
 3711      /// <returns>true if the stream supports seeking; otherwise, false.</returns>
 3712      public override bool CanSeek {
 23713        get { return true; }
 3714      }
 3715
 3716      /// <summary>
 3717      /// Gets a value indicating whether the current stream supports reading.
 3718      /// </summary>
 3719      /// <value>true.</value>
 3720      /// <returns>true if the stream supports reading; otherwise, false.</returns>
 3721      public override bool CanRead {
 133722        get { return true; }
 3723      }
 3724
 3725      /// <summary>
 3726      /// Gets a value that determines whether the current stream can time out.
 3727      /// </summary>
 3728      /// <value></value>
 3729      /// <returns>A value that determines whether the current stream can time out.</returns>
 3730      public override bool CanTimeout {
 03731        get { return baseStream_.CanTimeout; }
 3732      }
 3733      #region Instance Fields
 3734      ZipFile zipFile_;
 3735      Stream baseStream_;
 3736      long start_;
 3737      long length_;
 3738      long readPos_;
 3739      long end_;
 3740      #endregion
 3741    }
 3742    #endregion
 3743  }
 3744
 3745  #endregion
 3746
 3747  #region DataSources
 3748  /// <summary>
 3749  /// Provides a static way to obtain a source of data for an entry.
 3750  /// </summary>
 3751  public interface IStaticDataSource
 3752  {
 3753    /// <summary>
 3754    /// Get a source of data by creating a new stream.
 3755    /// </summary>
 3756    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3757    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3758    Stream GetSource();
 3759  }
 3760
 3761  /// <summary>
 3762  /// Represents a source of data that can dynamically provide
 3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.
 3764  /// </summary>
 3765  public interface IDynamicDataSource
 3766  {
 3767    /// <summary>
 3768    /// Get a data source.
 3769    /// </summary>
 3770    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>
 3771    /// <param name="name">The name for data if known.</param>
 3772    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
 3773    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
 3774    Stream GetSource(ZipEntry entry, string name);
 3775  }
 3776
 3777  /// <summary>
 3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.
 3779  /// </summary>
 3780  public class StaticDiskDataSource : IStaticDataSource
 3781  {
 3782    /// <summary>
 3783    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>
 3784    /// </summary>
 3785    /// <param name="fileName">The name of the file to obtain data from.</param>
 3786    public StaticDiskDataSource(string fileName)
 3787    {
 3788      fileName_ = fileName;
 3789    }
 3790
 3791    #region IDataSource Members
 3792
 3793    /// <summary>
 3794    /// Get a <see cref="Stream"/> providing data.
 3795    /// </summary>
 3796    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>
 3797    public Stream GetSource()
 3798    {
 3799      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 3800    }
 3801
 3802    readonly
 3803
 3804    #endregion
 3805    #region Instance Fields
 3806    string fileName_;
 3807    #endregion
 3808  }
 3809
 3810
 3811  /// <summary>
 3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.
 3813  /// </summary>
 3814  public class DynamicDiskDataSource : IDynamicDataSource
 3815  {
 3816
 3817    #region IDataSource Members
 3818    /// <summary>
 3819    /// Get a <see cref="Stream"/> providing data for an entry.
 3820    /// </summary>
 3821    /// <param name="entry">The entry to provide data for.</param>
 3822    /// <param name="name">The file name for data if known.</param>
 3823    /// <returns>Returns a stream providing data; or null if not available</returns>
 3824    public Stream GetSource(ZipEntry entry, string name)
 3825    {
 3826      Stream result = null;
 3827
 3828      if (name != null) {
 3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
 3830      }
 3831
 3832      return result;
 3833    }
 3834
 3835    #endregion
 3836  }
 3837
 3838  #endregion
 3839
 3840  #region Archive Storage
 3841  /// <summary>
 3842  /// Defines facilities for data storage when updating Zip Archives.
 3843  /// </summary>
 3844  public interface IArchiveStorage
 3845  {
 3846    /// <summary>
 3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.
 3848    /// </summary>
 3849    FileUpdateMode UpdateMode { get; }
 3850
 3851    /// <summary>
 3852    /// Get an empty <see cref="Stream"/> that can be used for temporary output.
 3853    /// </summary>
 3854    /// <returns>Returns a temporary output <see cref="Stream"/></returns>
 3855    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3856    Stream GetTemporaryOutput();
 3857
 3858    /// <summary>
 3859    /// Convert a temporary output stream to a final stream.
 3860    /// </summary>
 3861    /// <returns>The resulting final <see cref="Stream"/></returns>
 3862    /// <seealso cref="GetTemporaryOutput"/>
 3863    Stream ConvertTemporaryToFinal();
 3864
 3865    /// <summary>
 3866    /// Make a temporary copy of the original stream.
 3867    /// </summary>
 3868    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 3869    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3870    Stream MakeTemporaryCopy(Stream stream);
 3871
 3872    /// <summary>
 3873    /// Return a stream suitable for performing direct updates on the original source.
 3874    /// </summary>
 3875    /// <param name="stream">The current stream.</param>
 3876    /// <returns>Returns a stream suitable for direct updating.</returns>
 3877    /// <remarks>This may be the current stream passed.</remarks>
 3878    Stream OpenForDirectUpdate(Stream stream);
 3879
 3880    /// <summary>
 3881    /// Dispose of this instance.
 3882    /// </summary>
 3883    void Dispose();
 3884  }
 3885
 3886  /// <summary>
 3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.
 3888  /// </summary>
 3889  abstract public class BaseArchiveStorage : IArchiveStorage
 3890  {
 3891    #region Constructors
 3892    /// <summary>
 3893    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.
 3894    /// </summary>
 3895    /// <param name="updateMode">The update mode.</param>
 3896    protected BaseArchiveStorage(FileUpdateMode updateMode)
 3897    {
 3898      updateMode_ = updateMode;
 3899    }
 3900    #endregion
 3901
 3902    #region IArchiveStorage Members
 3903
 3904    /// <summary>
 3905    /// Gets a temporary output <see cref="Stream"/>
 3906    /// </summary>
 3907    /// <returns>Returns the temporary output stream.</returns>
 3908    /// <seealso cref="ConvertTemporaryToFinal"></seealso>
 3909    public abstract Stream GetTemporaryOutput();
 3910
 3911    /// <summary>
 3912    /// Converts the temporary <see cref="Stream"/> to its final form.
 3913    /// </summary>
 3914    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 3915    /// the final storage for the archive.</returns>
 3916    /// <seealso cref="GetTemporaryOutput"/>
 3917    public abstract Stream ConvertTemporaryToFinal();
 3918
 3919    /// <summary>
 3920    /// Make a temporary copy of a <see cref="Stream"/>.
 3921    /// </summary>
 3922    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>
 3923    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 3924    public abstract Stream MakeTemporaryCopy(Stream stream);
 3925
 3926    /// <summary>
 3927    /// Return a stream suitable for performing direct updates on the original source.
 3928    /// </summary>
 3929    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>
 3930    /// <returns>Returns a stream suitable for direct updating.</returns>
 3931    public abstract Stream OpenForDirectUpdate(Stream stream);
 3932
 3933    /// <summary>
 3934    /// Disposes this instance.
 3935    /// </summary>
 3936    public abstract void Dispose();
 3937
 3938    /// <summary>
 3939    /// Gets the update mode applicable.
 3940    /// </summary>
 3941    /// <value>The update mode.</value>
 3942    public FileUpdateMode UpdateMode {
 3943      get {
 3944        return updateMode_;
 3945      }
 3946    }
 3947
 3948    #endregion
 3949
 3950    #region Instance Fields
 3951    FileUpdateMode updateMode_;
 3952    #endregion
 3953  }
 3954
 3955  /// <summary>
 3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.
 3957  /// </summary>
 3958  public class DiskArchiveStorage : BaseArchiveStorage
 3959  {
 3960    #region Constructors
 3961    /// <summary>
 3962    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3963    /// </summary>
 3964    /// <param name="file">The file.</param>
 3965    /// <param name="updateMode">The update mode.</param>
 3966    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)
 3967      : base(updateMode)
 3968    {
 3969      if (file.Name == null) {
 3970        throw new ZipException("Cant handle non file archives");
 3971      }
 3972
 3973      fileName_ = file.Name;
 3974    }
 3975
 3976    /// <summary>
 3977    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
 3978    /// </summary>
 3979    /// <param name="file">The file.</param>
 3980    public DiskArchiveStorage(ZipFile file)
 3981      : this(file, FileUpdateMode.Safe)
 3982    {
 3983    }
 3984    #endregion
 3985
 3986    #region IArchiveStorage Members
 3987
 3988    /// <summary>
 3989    /// Gets a temporary output <see cref="Stream"/> for performing updates on.
 3990    /// </summary>
 3991    /// <returns>Returns the temporary output stream.</returns>
 3992    public override Stream GetTemporaryOutput()
 3993    {
 3994      if (temporaryName_ != null) {
 3995        temporaryName_ = GetTempFileName(temporaryName_, true);
 3996        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 3997      } else {
 3998        // Determine where to place files based on internal strategy.
 3999        // Currently this is always done in system temp directory.
 4000        temporaryName_ = Path.GetTempFileName();
 4001        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
 4002      }
 4003
 4004      return temporaryStream_;
 4005    }
 4006
 4007    /// <summary>
 4008    /// Converts a temporary <see cref="Stream"/> to its final form.
 4009    /// </summary>
 4010    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4011    /// the final storage for the archive.</returns>
 4012    public override Stream ConvertTemporaryToFinal()
 4013    {
 4014      if (temporaryStream_ == null) {
 4015        throw new ZipException("No temporary stream has been created");
 4016      }
 4017
 4018      Stream result = null;
 4019
 4020      string moveTempName = GetTempFileName(fileName_, false);
 4021      bool newFileCreated = false;
 4022
 4023      try {
 4024        temporaryStream_.Close();
 4025        File.Move(fileName_, moveTempName);
 4026        File.Move(temporaryName_, fileName_);
 4027        newFileCreated = true;
 4028        File.Delete(moveTempName);
 4029
 4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);
 4031      } catch (Exception) {
 4032        result = null;
 4033
 4034        // Try to roll back changes...
 4035        if (!newFileCreated) {
 4036          File.Move(moveTempName, fileName_);
 4037          File.Delete(temporaryName_);
 4038        }
 4039
 4040        throw;
 4041      }
 4042
 4043      return result;
 4044    }
 4045
 4046    /// <summary>
 4047    /// Make a temporary copy of a stream.
 4048    /// </summary>
 4049    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4050    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4051    public override Stream MakeTemporaryCopy(Stream stream)
 4052    {
 4053      stream.Close();
 4054
 4055      temporaryName_ = GetTempFileName(fileName_, true);
 4056      File.Copy(fileName_, temporaryName_, true);
 4057
 4058      temporaryStream_ = new FileStream(temporaryName_,
 4059        FileMode.Open,
 4060        FileAccess.ReadWrite);
 4061      return temporaryStream_;
 4062    }
 4063
 4064    /// <summary>
 4065    /// Return a stream suitable for performing direct updates on the original source.
 4066    /// </summary>
 4067    /// <param name="stream">The current stream.</param>
 4068    /// <returns>Returns a stream suitable for direct updating.</returns>
 4069    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>
 4070    public override Stream OpenForDirectUpdate(Stream stream)
 4071    {
 4072      Stream result;
 4073      if ((stream == null) || !stream.CanWrite) {
 4074        if (stream != null) {
 4075          stream.Close();
 4076        }
 4077
 4078        result = new FileStream(fileName_,
 4079            FileMode.Open,
 4080            FileAccess.ReadWrite);
 4081      } else {
 4082        result = stream;
 4083      }
 4084
 4085      return result;
 4086    }
 4087
 4088    /// <summary>
 4089    /// Disposes this instance.
 4090    /// </summary>
 4091    public override void Dispose()
 4092    {
 4093      if (temporaryStream_ != null) {
 4094        temporaryStream_.Close();
 4095      }
 4096    }
 4097
 4098    #endregion
 4099
 4100    #region Internal routines
 4101    static string GetTempFileName(string original, bool makeTempFile)
 4102    {
 4103      string result = null;
 4104
 4105      if (original == null) {
 4106        result = Path.GetTempFileName();
 4107      } else {
 4108        int counter = 0;
 4109        int suffixSeed = DateTime.Now.Second;
 4110
 4111        while (result == null) {
 4112          counter += 1;
 4113          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);
 4114          if (!File.Exists(newName)) {
 4115            if (makeTempFile) {
 4116              try {
 4117                // Try and create the file.
 4118                using (FileStream stream = File.Create(newName)) {
 4119                }
 4120                result = newName;
 4121              } catch {
 4122                suffixSeed = DateTime.Now.Second;
 4123              }
 4124            } else {
 4125              result = newName;
 4126            }
 4127          }
 4128        }
 4129      }
 4130      return result;
 4131    }
 4132    #endregion
 4133
 4134    #region Instance Fields
 4135    Stream temporaryStream_;
 4136    string fileName_;
 4137    string temporaryName_;
 4138    #endregion
 4139  }
 4140
 4141  /// <summary>
 4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.
 4143  /// </summary>
 4144  public class MemoryArchiveStorage : BaseArchiveStorage
 4145  {
 4146    #region Constructors
 4147    /// <summary>
 4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4149    /// </summary>
 4150    public MemoryArchiveStorage()
 4151      : base(FileUpdateMode.Direct)
 4152    {
 4153    }
 4154
 4155    /// <summary>
 4156    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
 4157    /// </summary>
 4158    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>
 4159    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>
 4160    public MemoryArchiveStorage(FileUpdateMode updateMode)
 4161      : base(updateMode)
 4162    {
 4163    }
 4164
 4165    #endregion
 4166
 4167    #region Properties
 4168    /// <summary>
 4169    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.
 4170    /// </summary>
 4171    public MemoryStream FinalStream {
 4172      get { return finalStream_; }
 4173    }
 4174
 4175    #endregion
 4176
 4177    #region IArchiveStorage Members
 4178
 4179    /// <summary>
 4180    /// Gets the temporary output <see cref="Stream"/>
 4181    /// </summary>
 4182    /// <returns>Returns the temporary output stream.</returns>
 4183    public override Stream GetTemporaryOutput()
 4184    {
 4185      temporaryStream_ = new MemoryStream();
 4186      return temporaryStream_;
 4187    }
 4188
 4189    /// <summary>
 4190    /// Converts the temporary <see cref="Stream"/> to its final form.
 4191    /// </summary>
 4192    /// <returns>Returns a <see cref="Stream"/> that can be used to read
 4193    /// the final storage for the archive.</returns>
 4194    public override Stream ConvertTemporaryToFinal()
 4195    {
 4196      if (temporaryStream_ == null) {
 4197        throw new ZipException("No temporary stream has been created");
 4198      }
 4199
 4200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());
 4201      return finalStream_;
 4202    }
 4203
 4204    /// <summary>
 4205    /// Make a temporary copy of the original stream.
 4206    /// </summary>
 4207    /// <param name="stream">The <see cref="Stream"/> to copy.</param>
 4208    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
 4209    public override Stream MakeTemporaryCopy(Stream stream)
 4210    {
 4211      temporaryStream_ = new MemoryStream();
 4212      stream.Position = 0;
 4213      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);
 4214      return temporaryStream_;
 4215    }
 4216
 4217    /// <summary>
 4218    /// Return a stream suitable for performing direct updates on the original source.
 4219    /// </summary>
 4220    /// <param name="stream">The original source stream</param>
 4221    /// <returns>Returns a stream suitable for direct updating.</returns>
 4222    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;
 4223    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>
 4224    public override Stream OpenForDirectUpdate(Stream stream)
 4225    {
 4226      Stream result;
 4227      if ((stream == null) || !stream.CanWrite) {
 4228
 4229        result = new MemoryStream();
 4230
 4231        if (stream != null) {
 4232          stream.Position = 0;
 4233          StreamUtils.Copy(stream, result, new byte[4096]);
 4234
 4235          stream.Close();
 4236        }
 4237      } else {
 4238        result = stream;
 4239      }
 4240
 4241      return result;
 4242    }
 4243
 4244    /// <summary>
 4245    /// Disposes this instance.
 4246    /// </summary>
 4247    public override void Dispose()
 4248    {
 4249      if (temporaryStream_ != null) {
 4250        temporaryStream_.Close();
 4251      }
 4252    }
 4253
 4254    #endregion
 4255
 4256    #region Instance Fields
 4257    MemoryStream temporaryStream_;
 4258    MemoryStream finalStream_;
 4259    #endregion
 4260  }
 4261
 4262  #endregion
 4263}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipHelperStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipHelperStream.htm new file mode 100644 index 000000000..a45baa092 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipHelperStream.htm @@ -0,0 +1,624 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipHelperStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipHelperStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipHelperStream.cs
Covered lines:106
Uncovered lines:88
Coverable lines:194
Total lines:560
Line coverage:54.6%
Branch coverage:42.8%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)100
.ctor(...)1100100
Flush()100
Seek(...)1100100
SetLength(...)1100100
Read(...)1100100
Write(...)1100100
Close()3100100
WriteLocalHeader(...)1600
LocateBlockWithSignature(...)488.8985.71
WriteZip64EndOfCentralDirectory(...)1100100
WriteEndOfCentralDirectory(...)1180.7773.68
ReadLEShort()371.4360
ReadLEInt()1100100
ReadLELong()1100100
WriteLEShort(...)1100100
WriteLEUshort(...)1100100
WriteLEInt(...)1100100
WriteLEUint(...)100
WriteLELong(...)1100100
WriteLEUlong(...)100
WriteDataDescriptor(...)468.7557.14
ReadDataDescriptor(...)390.9180
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipHelperStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Text;
 4
 5namespace ICSharpCode.SharpZipLib.Zip
 6{
 7  /// <summary>
 8  /// Holds data pertinent to a data descriptor.
 9  /// </summary>
 10  public class DescriptorData
 11  {
 12    /// <summary>
 13    /// Get /set the compressed size of data.
 14    /// </summary>
 15    public long CompressedSize {
 16      get { return compressedSize; }
 17      set { compressedSize = value; }
 18    }
 19
 20    /// <summary>
 21    /// Get / set the uncompressed size of data
 22    /// </summary>
 23    public long Size {
 24      get { return size; }
 25      set { size = value; }
 26    }
 27
 28    /// <summary>
 29    /// Get /set the crc value.
 30    /// </summary>
 31    public long Crc {
 32      get { return crc; }
 33      set { crc = (value & 0xffffffff); }
 34    }
 35
 36    #region Instance Fields
 37    long size;
 38    long compressedSize;
 39    long crc;
 40    #endregion
 41  }
 42
 43  class EntryPatchData
 44  {
 45    public long SizePatchOffset {
 46      get { return sizePatchOffset_; }
 47      set { sizePatchOffset_ = value; }
 48    }
 49
 50    public long CrcPatchOffset {
 51      get { return crcPatchOffset_; }
 52      set { crcPatchOffset_ = value; }
 53    }
 54
 55    #region Instance Fields
 56    long sizePatchOffset_;
 57    long crcPatchOffset_;
 58    #endregion
 59  }
 60
 61  /// <summary>
 62  /// This class assists with writing/reading from Zip files.
 63  /// </summary>
 64  internal class ZipHelperStream : Stream
 65  {
 66    #region Constructors
 67    /// <summary>
 68    /// Initialise an instance of this class.
 69    /// </summary>
 70    /// <param name="name">The name of the file to open.</param>
 071    public ZipHelperStream(string name)
 72    {
 073      stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite);
 074      isOwner_ = true;
 075    }
 76
 77    /// <summary>
 78    /// Initialise a new instance of <see cref="ZipHelperStream"/>.
 79    /// </summary>
 80    /// <param name="stream">The stream to use.</param>
 27281    public ZipHelperStream(Stream stream)
 82    {
 27283      stream_ = stream;
 27284    }
 85    #endregion
 86
 87    /// <summary>
 88    /// Get / set a value indicating wether the the underlying stream is owned or not.
 89    /// </summary>
 90    /// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>
 91    public bool IsStreamOwner {
 092      get { return isOwner_; }
 893      set { isOwner_ = value; }
 94    }
 95
 96    #region Base Stream Methods
 97    public override bool CanRead {
 098      get { return stream_.CanRead; }
 99    }
 100
 101    public override bool CanSeek {
 0102      get { return stream_.CanSeek; }
 103    }
 104
 105    public override bool CanTimeout {
 0106      get { return stream_.CanTimeout; }
 107    }
 108
 109    public override long Length {
 1110      get { return stream_.Length; }
 111    }
 112
 113    public override long Position {
 124114      get { return stream_.Position; }
 6115      set { stream_.Position = value; }
 116    }
 117
 118    public override bool CanWrite {
 0119      get { return stream_.CanWrite; }
 120    }
 121
 122    public override void Flush()
 123    {
 0124      stream_.Flush();
 0125    }
 126
 127    public override long Seek(long offset, SeekOrigin origin)
 128    {
 131329129      return stream_.Seek(offset, origin);
 130    }
 131
 132    public override void SetLength(long value)
 133    {
 3134      stream_.SetLength(value);
 3135    }
 136
 137    public override int Read(byte[] buffer, int offset, int count)
 138    {
 1139      return stream_.Read(buffer, offset, count);
 140    }
 141
 142    public override void Write(byte[] buffer, int offset, int count)
 143    {
 9144      stream_.Write(buffer, offset, count);
 9145    }
 146
 147    /// <summary>
 148    /// Close the stream.
 149    /// </summary>
 150    /// <remarks>
 151    /// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.
 152    /// </remarks>
 153    override public void Close()
 154    {
 254155      Stream toClose = stream_;
 254156      stream_ = null;
 254157       if (isOwner_ && (toClose != null)) {
 1158        isOwner_ = false;
 1159        toClose.Close();
 160      }
 254161    }
 162    #endregion
 163
 164    // Write the local file header
 165    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
 166    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
 167    {
 0168      CompressionMethod method = entry.CompressionMethod;
 0169      bool headerInfoAvailable = true; // How to get this?
 0170      bool patchEntryHeader = false;
 171
 0172      WriteLEInt(ZipConstants.LocalHeaderSignature);
 173
 0174      WriteLEShort(entry.Version);
 0175      WriteLEShort(entry.Flags);
 0176      WriteLEShort((byte)method);
 0177      WriteLEInt((int)entry.DosTime);
 178
 0179       if (headerInfoAvailable == true) {
 0180        WriteLEInt((int)entry.Crc);
 0181         if (entry.LocalHeaderRequiresZip64) {
 0182          WriteLEInt(-1);
 0183          WriteLEInt(-1);
 0184        } else {
 0185          WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.Compressed
 0186          WriteLEInt((int)entry.Size);
 187        }
 0188      } else {
 0189         if (patchData != null) {
 0190          patchData.CrcPatchOffset = stream_.Position;
 191        }
 0192        WriteLEInt(0);  // Crc
 193
 0194         if (patchData != null) {
 0195          patchData.SizePatchOffset = stream_.Position;
 196        }
 197
 198        // For local header both sizes appear in Zip64 Extended Information
 0199         if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {
 0200          WriteLEInt(-1);
 0201          WriteLEInt(-1);
 0202        } else {
 0203          WriteLEInt(0);  // Compressed size
 0204          WriteLEInt(0);  // Uncompressed size
 205        }
 206      }
 207
 0208      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 209
 0210       if (name.Length > 0xFFFF) {
 0211        throw new ZipException("Entry name too long.");
 212      }
 213
 0214      var ed = new ZipExtraData(entry.ExtraData);
 215
 0216       if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) {
 0217        ed.StartNewEntry();
 0218         if (headerInfoAvailable) {
 0219          ed.AddLeLong(entry.Size);
 0220          ed.AddLeLong(entry.CompressedSize);
 0221        } else {
 0222          ed.AddLeLong(-1);
 0223          ed.AddLeLong(-1);
 224        }
 0225        ed.AddNewEntry(1);
 226
 0227         if (!ed.Find(1)) {
 0228          throw new ZipException("Internal error cant find extra data");
 229        }
 230
 0231         if (patchData != null) {
 0232          patchData.SizePatchOffset = ed.CurrentReadIndex;
 233        }
 0234      } else {
 0235        ed.Delete(1);
 236      }
 237
 0238      byte[] extra = ed.GetEntryData();
 239
 0240      WriteLEShort(name.Length);
 0241      WriteLEShort(extra.Length);
 242
 0243       if (name.Length > 0) {
 0244        stream_.Write(name, 0, name.Length);
 245      }
 246
 0247       if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {
 0248        patchData.SizePatchOffset += stream_.Position;
 249      }
 250
 0251       if (extra.Length > 0) {
 0252        stream_.Write(extra, 0, extra.Length);
 253      }
 0254    }
 255
 256    /// <summary>
 257    /// Locates a block with the desired <paramref name="signature"/>.
 258    /// </summary>
 259    /// <param name="signature">The signature to find.</param>
 260    /// <param name="endLocation">Location, marking the end of block.</param>
 261    /// <param name="minimumBlockSize">Minimum size of the block.</param>
 262    /// <param name="maximumVariableData">The maximum variable data.</param>
 263    /// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns>
 264    public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 265    {
 118266      long pos = endLocation - minimumBlockSize;
 118267       if (pos < 0) {
 0268        return -1;
 269      }
 270
 118271      long giveUpMarker = Math.Max(pos - maximumVariableData, 0);
 272
 273      // TODO: This loop could be optimised for speed.
 274      do {
 131330275         if (pos < giveUpMarker) {
 1276          return -1;
 277        }
 131329278        Seek(pos--, SeekOrigin.Begin);
 131329279       } while (ReadLEInt() != signature);
 280
 117281      return Position;
 282    }
 283
 284    /// <summary>
 285    /// Write Zip64 end of central directory records (File header and locator).
 286    /// </summary>
 287    /// <param name="noOfEntries">The number of entries in the central directory.</param>
 288    /// <param name="sizeEntries">The size of entries in the central directory.</param>
 289    /// <param name="centralDirOffset">The offset of the dentral directory.</param>
 290    public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)
 291    {
 1292      long centralSignatureOffset = stream_.Position;
 1293      WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature);
 1294      WriteLELong(44);    // Size of this record (total size of remaining fields in header or full size - 12)
 1295      WriteLEShort(ZipConstants.VersionMadeBy);   // Version made by
 1296      WriteLEShort(ZipConstants.VersionZip64);   // Version to extract
 1297      WriteLEInt(0);      // Number of this disk
 1298      WriteLEInt(0);      // number of the disk with the start of the central directory
 1299      WriteLELong(noOfEntries);       // No of entries on this disk
 1300      WriteLELong(noOfEntries);       // Total No of entries in central directory
 1301      WriteLELong(sizeEntries);       // Size of the central directory
 1302      WriteLELong(centralDirOffset);  // offset of start of central directory
 303                      // zip64 extensible data sector not catered for here (variable size)
 304
 305      // Write the Zip64 end of central directory locator
 1306      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);
 307
 308      // no of the disk with the start of the zip64 end of central directory
 1309      WriteLEInt(0);
 310
 311      // relative offset of the zip64 end of central directory record
 1312      WriteLELong(centralSignatureOffset);
 313
 314      // total number of disks
 1315      WriteLEInt(1);
 1316    }
 317
 318    /// <summary>
 319    /// Write the required records to end the central directory.
 320    /// </summary>
 321    /// <param name="noOfEntries">The number of entries in the directory.</param>
 322    /// <param name="sizeEntries">The size of the entries in the directory.</param>
 323    /// <param name="startOfCentralDirectory">The start of the central directory.</param>
 324    /// <param name="comment">The archive comment.  (This can be null).</param>
 325    public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,
 326      long startOfCentralDirectory, byte[] comment)
 327    {
 328
 131329       if ((noOfEntries >= 0xffff) ||
 131330        (startOfCentralDirectory >= 0xffffffff) ||
 131331        (sizeEntries >= 0xffffffff)) {
 1332        WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);
 333      }
 334
 131335      WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);
 336
 337      // TODO: ZipFile Multi disk handling not done
 130338      WriteLEShort(0);                    // number of this disk
 130339      WriteLEShort(0);                    // no of disk with start of central dir
 340
 341
 342      // Number of entries
 130343       if (noOfEntries >= 0xffff) {
 1344        WriteLEUshort(0xffff);  // Zip64 marker
 1345        WriteLEUshort(0xffff);
 1346      } else {
 129347        WriteLEShort((short)noOfEntries);          // entries in central dir for this disk
 129348        WriteLEShort((short)noOfEntries);          // total entries in central directory
 349      }
 350
 351      // Size of the central directory
 130352       if (sizeEntries >= 0xffffffff) {
 0353        WriteLEUint(0xffffffff);    // Zip64 marker
 0354      } else {
 130355        WriteLEInt((int)sizeEntries);
 356      }
 357
 358
 359      // offset of start of central directory
 130360       if (startOfCentralDirectory >= 0xffffffff) {
 0361        WriteLEUint(0xffffffff);    // Zip64 marker
 0362      } else {
 130363        WriteLEInt((int)startOfCentralDirectory);
 364      }
 365
 130366       int commentLength = (comment != null) ? comment.Length : 0;
 367
 130368       if (commentLength > 0xffff) {
 0369        throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));
 370      }
 371
 130372      WriteLEShort(commentLength);
 373
 130374       if (commentLength > 0) {
 5375        Write(comment, 0, comment.Length);
 376      }
 130377    }
 378
 379    #region LE value reading/writing
 380    /// <summary>
 381    /// Read an unsigned short in little endian byte order.
 382    /// </summary>
 383    /// <returns>Returns the value read.</returns>
 384    /// <exception cref="IOException">
 385    /// An i/o error occurs.
 386    /// </exception>
 387    /// <exception cref="EndOfStreamException">
 388    /// The file ends prematurely
 389    /// </exception>
 390    public int ReadLEShort()
 391    {
 262792392      int byteValue1 = stream_.ReadByte();
 393
 262792394       if (byteValue1 < 0) {
 0395        throw new EndOfStreamException();
 396      }
 397
 262792398      int byteValue2 = stream_.ReadByte();
 262792399       if (byteValue2 < 0) {
 0400        throw new EndOfStreamException();
 401      }
 402
 262792403      return byteValue1 | (byteValue2 << 8);
 404    }
 405
 406    /// <summary>
 407    /// Read an int in little endian byte order.
 408    /// </summary>
 409    /// <returns>Returns the value read.</returns>
 410    /// <exception cref="IOException">
 411    /// An i/o error occurs.
 412    /// </exception>
 413    /// <exception cref="System.IO.EndOfStreamException">
 414    /// The file ends prematurely
 415    /// </exception>
 416    public int ReadLEInt()
 417    {
 131395418      return ReadLEShort() | (ReadLEShort() << 16);
 419    }
 420
 421    /// <summary>
 422    /// Read a long in little endian byte order.
 423    /// </summary>
 424    /// <returns>The value read.</returns>
 425    public long ReadLELong()
 426    {
 9427      return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);
 428    }
 429
 430    /// <summary>
 431    /// Write an unsigned short in little endian byte order.
 432    /// </summary>
 433    /// <param name="value">The value to write.</param>
 434    public void WriteLEShort(int value)
 435    {
 1545436      stream_.WriteByte((byte)(value & 0xff));
 1544437      stream_.WriteByte((byte)((value >> 8) & 0xff));
 1544438    }
 439
 440    /// <summary>
 441    /// Write a ushort in little endian byte order.
 442    /// </summary>
 443    /// <param name="value">The value to write.</param>
 444    public void WriteLEUshort(ushort value)
 445    {
 2446      stream_.WriteByte((byte)(value & 0xff));
 2447      stream_.WriteByte((byte)(value >> 8));
 2448    }
 449
 450    /// <summary>
 451    /// Write an int in little endian byte order.
 452    /// </summary>
 453    /// <param name="value">The value to write.</param>
 454    public void WriteLEInt(int value)
 455    {
 444456      WriteLEShort(value);
 444457      WriteLEShort(value >> 16);
 443458    }
 459
 460    /// <summary>
 461    /// Write a uint in little endian byte order.
 462    /// </summary>
 463    /// <param name="value">The value to write.</param>
 464    public void WriteLEUint(uint value)
 465    {
 0466      WriteLEUshort((ushort)(value & 0xffff));
 0467      WriteLEUshort((ushort)(value >> 16));
 0468    }
 469
 470    /// <summary>
 471    /// Write a long in little endian byte order.
 472    /// </summary>
 473    /// <param name="value">The value to write.</param>
 474    public void WriteLELong(long value)
 475    {
 12476      WriteLEInt((int)value);
 12477      WriteLEInt((int)(value >> 32));
 12478    }
 479
 480    /// <summary>
 481    /// Write a ulong in little endian byte order.
 482    /// </summary>
 483    /// <param name="value">The value to write.</param>
 484    public void WriteLEUlong(ulong value)
 485    {
 0486      WriteLEUint((uint)(value & 0xffffffff));
 0487      WriteLEUint((uint)(value >> 32));
 0488    }
 489
 490    #endregion
 491
 492    /// <summary>
 493    /// Write a data descriptor.
 494    /// </summary>
 495    /// <param name="entry">The entry to write a descriptor for.</param>
 496    /// <returns>Returns the number of descriptor bytes written.</returns>
 497    public int WriteDataDescriptor(ZipEntry entry)
 498    {
 5499       if (entry == null) {
 0500        throw new ArgumentNullException(nameof(entry));
 501      }
 502
 5503      int result = 0;
 504
 505      // Add data descriptor if flagged as required
 5506       if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 507        // The signature is not PKZIP originally but is now described as optional
 508        // in the PKZIP Appnote documenting trhe format.
 5509        WriteLEInt(ZipConstants.DataDescriptorSignature);
 5510        WriteLEInt(unchecked((int)(entry.Crc)));
 511
 5512        result += 8;
 513
 5514         if (entry.LocalHeaderRequiresZip64) {
 0515          WriteLELong(entry.CompressedSize);
 0516          WriteLELong(entry.Size);
 0517          result += 16;
 0518        } else {
 5519          WriteLEInt((int)entry.CompressedSize);
 5520          WriteLEInt((int)entry.Size);
 5521          result += 8;
 522        }
 523      }
 524
 5525      return result;
 526    }
 527
 528    /// <summary>
 529    /// Read data descriptor at the end of compressed data.
 530    /// </summary>
 531    /// <param name="zip64">if set to <c>true</c> [zip64].</param>
 532    /// <param name="data">The data to fill in.</param>
 533    /// <returns>Returns the number of bytes read in the descriptor.</returns>
 534    public void ReadDataDescriptor(bool zip64, DescriptorData data)
 535    {
 13536      int intValue = ReadLEInt();
 537
 538      // In theory this may not be a descriptor according to PKZIP appnote.
 539      // In practise its always there.
 13540       if (intValue != ZipConstants.DataDescriptorSignature) {
 0541        throw new ZipException("Data descriptor signature not found");
 542      }
 543
 13544      data.Crc = ReadLEInt();
 545
 13546       if (zip64) {
 3547        data.CompressedSize = ReadLELong();
 3548        data.Size = ReadLELong();
 3549      } else {
 10550        data.CompressedSize = ReadLEInt();
 10551        data.Size = ReadLEInt();
 552      }
 10553    }
 554
 555    #region Instance Fields
 556    bool isOwner_;
 557    Stream stream_;
 558    #endregion
 559  }
 560}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipInputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipInputStream.htm new file mode 100644 index 000000000..deb2b1ef0 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipInputStream.htm @@ -0,0 +1,664 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipInputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipInputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipInputStream.cs
Covered lines:162
Uncovered lines:44
Coverable lines:206
Total lines:610
Line coverage:78.6%
Branch coverage:67.3%
+

Metrics

+ + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)100
GetNextEntry()2491.3875.56
ReadDataDescriptor()37560
CompleteCloseEntry(...)690.9181.82
CloseEntry()1047.8342.11
ReadByte()27566.67
ReadingNotAvailable(...)100
ReadingNotSupported(...)100
InitialRead(...)118480.95
Read(...)5100100
BodyRead(...)2282.8669.23
Close()1100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipInputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using ICSharpCode.SharpZipLib.Checksum;
 4using ICSharpCode.SharpZipLib.Encryption;
 5using ICSharpCode.SharpZipLib.Zip.Compression;
 6using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 7
 8namespace ICSharpCode.SharpZipLib.Zip
 9{
 10  /// <summary>
 11  /// This is an InflaterInputStream that reads the files baseInputStream an zip archive
 12  /// one after another.  It has a special method to get the zip entry of
 13  /// the next file.  The zip entry contains information about the file name
 14  /// size, compressed size, Crc, etc.
 15  /// It includes support for Stored and Deflated entries.
 16  /// <br/>
 17  /// <br/>Author of the original java version : Jochen Hoenicke
 18  /// </summary>
 19  ///
 20  /// <example> This sample shows how to read a zip file
 21  /// <code lang="C#">
 22  /// using System;
 23  /// using System.Text;
 24  /// using System.IO;
 25  ///
 26  /// using ICSharpCode.SharpZipLib.Zip;
 27  ///
 28  /// class MainClass
 29  /// {
 30  ///   public static void Main(string[] args)
 31  ///   {
 32  ///     using ( ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]))) {
 33  ///
 34  ///       ZipEntry theEntry;
 35  ///       const int size = 2048;
 36  ///       byte[] data = new byte[2048];
 37  ///
 38  ///       while ((theEntry = s.GetNextEntry()) != null) {
 39  ///                 if ( entry.IsFile ) {
 40  ///             Console.Write("Show contents (y/n) ?");
 41  ///             if (Console.ReadLine() == "y") {
 42  ///               while (true) {
 43  ///                 size = s.Read(data, 0, data.Length);
 44  ///                 if (size > 0) {
 45  ///                   Console.Write(new ASCIIEncoding().GetString(data, 0, size));
 46  ///                 } else {
 47  ///                   break;
 48  ///                 }
 49  ///               }
 50  ///             }
 51  ///         }
 52  ///       }
 53  ///     }
 54  ///   }
 55  /// }
 56  /// </code>
 57  /// </example>
 58  public class ZipInputStream : InflaterInputStream
 59  {
 60    #region Instance Fields
 61
 62    /// <summary>
 63    /// Delegate for reading bytes from a stream.
 64    /// </summary>
 65    delegate int ReadDataHandler(byte[] b, int offset, int length);
 66
 67    /// <summary>
 68    /// The current reader this instance.
 69    /// </summary>
 70    ReadDataHandler internalReader;
 71
 5772    Crc32 crc = new Crc32();
 73    ZipEntry entry;
 74
 75    long size;
 76    int method;
 77    int flags;
 78    string password;
 79    #endregion
 80
 81    #region Constructors
 82    /// <summary>
 83    /// Creates a new Zip input stream, for reading a zip archive.
 84    /// </summary>
 85    /// <param name="baseInputStream">The underlying <see cref="Stream"/> providing data.</param>
 86    public ZipInputStream(Stream baseInputStream)
 5787      : base(baseInputStream, new Inflater(true))
 88    {
 5789      internalReader = new ReadDataHandler(ReadingNotAvailable);
 5790    }
 91
 92    /// <summary>
 93    /// Creates a new Zip input stream, for reading a zip archive.
 94    /// </summary>
 95    /// <param name="baseInputStream">The underlying <see cref="Stream"/> providing data.</param>
 96    /// <param name="bufferSize">Size of the buffer.</param>
 97    public ZipInputStream(Stream baseInputStream, int bufferSize)
 098      : base(baseInputStream, new Inflater(true), bufferSize)
 99    {
 0100      internalReader = new ReadDataHandler(ReadingNotAvailable);
 0101    }
 102    #endregion
 103
 104    /// <summary>
 105    /// Optional password used for encryption when non-null
 106    /// </summary>
 107    /// <value>A password for all encrypted <see cref="ZipEntry">entries </see> in this <see cref="ZipInputStream"/></va
 108    public string Password {
 109      get {
 0110        return password;
 111      }
 112      set {
 23113        password = value;
 23114      }
 115    }
 116
 117
 118    /// <summary>
 119    /// Gets a value indicating if there is a current entry and it can be decompressed
 120    /// </summary>
 121    /// <remarks>
 122    /// The entry can only be decompressed if the library supports the zip features required to extract it.
 123    /// See the <see cref="ZipEntry.Version">ZipEntry Version</see> property for more details.
 124    /// </remarks>
 125    public bool CanDecompressEntry {
 126      get {
 70127        return (entry != null) && entry.CanDecompress;
 128      }
 129    }
 130
 131    /// <summary>
 132    /// Advances to the next entry in the archive
 133    /// </summary>
 134    /// <returns>
 135    /// The next <see cref="ZipEntry">entry</see> in the archive or null if there are no more entries.
 136    /// </returns>
 137    /// <remarks>
 138    /// If the previous entry is still open <see cref="CloseEntry">CloseEntry</see> is called.
 139    /// </remarks>
 140    /// <exception cref="InvalidOperationException">
 141    /// Input stream is closed
 142    /// </exception>
 143    /// <exception cref="ZipException">
 144    /// Password is not set, password is invalid, compression method is invalid,
 145    /// version required to extract is not supported
 146    /// </exception>
 147    public ZipEntry GetNextEntry()
 148    {
 87149       if (crc == null) {
 0150        throw new InvalidOperationException("Closed.");
 151      }
 152
 87153       if (entry != null) {
 14154        CloseEntry();
 155      }
 156
 87157      int header = inputBuffer.ReadLeInt();
 158
 87159       if (header == ZipConstants.CentralHeaderSignature ||
 87160        header == ZipConstants.EndOfCentralDirectorySignature ||
 87161        header == ZipConstants.CentralHeaderDigitalSignature ||
 87162        header == ZipConstants.ArchiveExtraDataSignature ||
 87163        header == ZipConstants.Zip64CentralFileHeaderSignature) {
 164        // No more individual entries exist
 6165        Close();
 6166        return null;
 167      }
 168
 169      // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found
 170      // Spanning signature is same as descriptor signature and is untested as yet.
 81171       if ((header == ZipConstants.SpanningTempSignature) || (header == ZipConstants.SpanningSignature)) {
 0172        header = inputBuffer.ReadLeInt();
 173      }
 174
 81175       if (header != ZipConstants.LocalHeaderSignature) {
 0176        throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
 177      }
 178
 81179      var versionRequiredToExtract = (short)inputBuffer.ReadLeShort();
 180
 81181      flags = inputBuffer.ReadLeShort();
 81182      method = inputBuffer.ReadLeShort();
 81183      var dostime = (uint)inputBuffer.ReadLeInt();
 81184      int crc2 = inputBuffer.ReadLeInt();
 81185      csize = inputBuffer.ReadLeInt();
 81186      size = inputBuffer.ReadLeInt();
 81187      int nameLen = inputBuffer.ReadLeShort();
 81188      int extraLen = inputBuffer.ReadLeShort();
 189
 81190      bool isCrypted = (flags & 1) == 1;
 191
 81192      byte[] buffer = new byte[nameLen];
 81193      inputBuffer.ReadRawBuffer(buffer);
 194
 81195      string name = ZipConstants.ConvertToStringExt(flags, buffer);
 196
 81197      entry = new ZipEntry(name, versionRequiredToExtract);
 81198      entry.Flags = flags;
 199
 81200      entry.CompressionMethod = (CompressionMethod)method;
 201
 81202       if ((flags & 8) == 0) {
 44203        entry.Crc = crc2 & 0xFFFFFFFFL;
 44204        entry.Size = size & 0xFFFFFFFFL;
 44205        entry.CompressedSize = csize & 0xFFFFFFFFL;
 206
 44207        entry.CryptoCheckValue = (byte)((crc2 >> 24) & 0xff);
 208
 44209      } else {
 210
 211        // This allows for GNU, WinZip and possibly other archives, the PKZIP spec
 212        // says these values are zero under these circumstances.
 37213         if (crc2 != 0) {
 12214          entry.Crc = crc2 & 0xFFFFFFFFL;
 215        }
 216
 37217         if (size != 0) {
 37218          entry.Size = size & 0xFFFFFFFFL;
 219        }
 220
 37221         if (csize != 0) {
 37222          entry.CompressedSize = csize & 0xFFFFFFFFL;
 223        }
 224
 37225        entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
 226      }
 227
 81228      entry.DosTime = dostime;
 229
 230      // If local header requires Zip64 is true then the extended header should contain
 231      // both values.
 232
 233      // Handle extra data if present.  This can set/alter some fields of the entry.
 81234       if (extraLen > 0) {
 78235        byte[] extra = new byte[extraLen];
 78236        inputBuffer.ReadRawBuffer(extra);
 78237        entry.ExtraData = extra;
 238      }
 239
 81240      entry.ProcessExtraData(true);
 81241       if (entry.CompressedSize >= 0) {
 57242        csize = entry.CompressedSize;
 243      }
 244
 81245       if (entry.Size >= 0) {
 57246        size = entry.Size;
 247      }
 248
 81249       if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.
 0250        throw new ZipException("Stored, but compressed != uncompressed");
 251      }
 252
 253      // Determine how to handle reading of data if this is attempted.
 81254       if (entry.IsCompressionMethodSupported()) {
 81255        internalReader = new ReadDataHandler(InitialRead);
 81256      } else {
 0257        internalReader = new ReadDataHandler(ReadingNotSupported);
 258      }
 259
 81260      return entry;
 261    }
 262
 263    /// <summary>
 264    /// Read data descriptor at the end of compressed data.
 265    /// </summary>
 266    void ReadDataDescriptor()
 267    {
 5268       if (inputBuffer.ReadLeInt() != ZipConstants.DataDescriptorSignature) {
 0269        throw new ZipException("Data descriptor signature not found");
 270      }
 271
 5272      entry.Crc = inputBuffer.ReadLeInt() & 0xFFFFFFFFL;
 273
 5274       if (entry.LocalHeaderRequiresZip64) {
 5275        csize = inputBuffer.ReadLeLong();
 5276        size = inputBuffer.ReadLeLong();
 5277      } else {
 0278        csize = inputBuffer.ReadLeInt();
 0279        size = inputBuffer.ReadLeInt();
 280      }
 5281      entry.CompressedSize = csize;
 5282      entry.Size = size;
 5283    }
 284
 285    /// <summary>
 286    /// Complete cleanup as the final part of closing.
 287    /// </summary>
 288    /// <param name="testCrc">True if the crc value should be tested</param>
 289    void CompleteCloseEntry(bool testCrc)
 290    {
 32291      StopDecrypting();
 292
 32293       if ((flags & 8) != 0) {
 5294        ReadDataDescriptor();
 295      }
 296
 32297      size = 0;
 298
 32299       if (testCrc &&
 32300        ((crc.Value & 0xFFFFFFFFL) != entry.Crc) && (entry.Crc != -1)) {
 0301        throw new ZipException("CRC mismatch");
 302      }
 303
 32304      crc.Reset();
 305
 32306       if (method == (int)CompressionMethod.Deflated) {
 25307        inf.Reset();
 308      }
 32309      entry = null;
 32310    }
 311
 312    /// <summary>
 313    /// Closes the current zip entry and moves to the next one.
 314    /// </summary>
 315    /// <exception cref="InvalidOperationException">
 316    /// The stream is closed
 317    /// </exception>
 318    /// <exception cref="ZipException">
 319    /// The Zip stream ends early
 320    /// </exception>
 321    public void CloseEntry()
 322    {
 14323       if (crc == null) {
 0324        throw new InvalidOperationException("Closed");
 325      }
 326
 14327       if (entry == null) {
 0328        return;
 329      }
 330
 14331       if (method == (int)CompressionMethod.Deflated) {
 9332         if ((flags & 8) != 0) {
 333          // We don't know how much we must skip, read until end.
 0334          byte[] tmp = new byte[4096];
 335
 336          // Read will close this entry
 0337           while (Read(tmp, 0, tmp.Length) > 0) {
 338          }
 0339          return;
 340        }
 341
 9342        csize -= inf.TotalIn;
 9343        inputBuffer.Available += inf.RemainingInput;
 344      }
 345
 14346       if ((inputBuffer.Available > csize) && (csize >= 0)) {
 14347        inputBuffer.Available = (int)((long)inputBuffer.Available - csize);
 14348      } else {
 0349        csize -= inputBuffer.Available;
 0350        inputBuffer.Available = 0;
 0351         while (csize != 0) {
 0352          long skipped = Skip(csize);
 353
 0354           if (skipped <= 0) {
 0355            throw new ZipException("Zip archive ends early.");
 356          }
 357
 0358          csize -= skipped;
 359        }
 360      }
 361
 14362      CompleteCloseEntry(false);
 14363    }
 364
 365    /// <summary>
 366    /// Returns 1 if there is an entry available
 367    /// Otherwise returns 0.
 368    /// </summary>
 369    public override int Available {
 370      get {
 0371         return entry != null ? 1 : 0;
 372      }
 373    }
 374
 375    /// <summary>
 376    /// Returns the current size that can be read from the current entry if available
 377    /// </summary>
 378    /// <exception cref="ZipException">Thrown if the entry size is not known.</exception>
 379    /// <exception cref="InvalidOperationException">Thrown if no entry is currently available.</exception>
 380    public override long Length {
 381      get {
 0382         if (entry != null) {
 0383           if (entry.Size >= 0) {
 0384            return entry.Size;
 385          } else {
 0386            throw new ZipException("Length not available for the current entry");
 387          }
 388        } else {
 0389          throw new InvalidOperationException("No current entry");
 390        }
 391      }
 392
 393    }
 394
 395    /// <summary>
 396    /// Reads a byte from the current zip entry.
 397    /// </summary>
 398    /// <returns>
 399    /// The byte or -1 if end of stream is reached.
 400    /// </returns>
 401    public override int ReadByte()
 402    {
 12403      byte[] b = new byte[1];
 12404       if (Read(b, 0, 1) <= 0) {
 0405        return -1;
 406      }
 12407      return b[0] & 0xff;
 408    }
 409
 410    /// <summary>
 411    /// Handle attempts to read by throwing an <see cref="InvalidOperationException"/>.
 412    /// </summary>
 413    /// <param name="destination">The destination array to store data in.</param>
 414    /// <param name="offset">The offset at which data read should be stored.</param>
 415    /// <param name="count">The maximum number of bytes to read.</param>
 416    /// <returns>Returns the number of bytes actually read.</returns>
 417    int ReadingNotAvailable(byte[] destination, int offset, int count)
 418    {
 0419      throw new InvalidOperationException("Unable to read from this stream");
 420    }
 421
 422    /// <summary>
 423    /// Handle attempts to read from this entry by throwing an exception
 424    /// </summary>
 425    int ReadingNotSupported(byte[] destination, int offset, int count)
 426    {
 0427      throw new ZipException("The compression method for this entry is not supported");
 428    }
 429
 430    /// <summary>
 431    /// Perform the initial read on an entry which may include
 432    /// reading encryption headers and setting up inflation.
 433    /// </summary>
 434    /// <param name="destination">The destination to fill with data read.</param>
 435    /// <param name="offset">The offset to start reading at.</param>
 436    /// <param name="count">The maximum number of bytes to read.</param>
 437    /// <returns>The actual number of bytes read.</returns>
 438    int InitialRead(byte[] destination, int offset, int count)
 439    {
 70440       if (!CanDecompressEntry) {
 0441        throw new ZipException("Library cannot extract this entry. Version required is (" + entry.Version + ")");
 442      }
 443
 444      // Handle encryption if required.
 70445       if (entry.IsCrypted) {
 24446         if (password == null) {
 0447          throw new ZipException("No password set.");
 448        }
 449
 450        // Generate and set crypto transform...
 24451        var managed = new PkzipClassicManaged();
 24452        byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));
 453
 24454        inputBuffer.CryptoTransform = managed.CreateDecryptor(key, null);
 455
 24456        byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
 24457        inputBuffer.ReadClearTextBuffer(cryptbuffer, 0, ZipConstants.CryptoHeaderSize);
 458
 24459         if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
 0460          throw new ZipException("Invalid password");
 461        }
 462
 24463         if (csize >= ZipConstants.CryptoHeaderSize) {
 13464          csize -= ZipConstants.CryptoHeaderSize;
 24465         } else if ((entry.Flags & (int)GeneralBitFlags.Descriptor) == 0) {
 0466          throw new ZipException(string.Format("Entry compressed size {0} too small for encryption", csize));
 467        }
 468      } else {
 46469        inputBuffer.CryptoTransform = null;
 470      }
 471
 70472       if ((csize > 0) || ((flags & (int)GeneralBitFlags.Descriptor) != 0)) {
 69473         if ((method == (int)CompressionMethod.Deflated) && (inputBuffer.Available > 0)) {
 66474          inputBuffer.SetInflaterInput(inf);
 475        }
 476
 69477        internalReader = new ReadDataHandler(BodyRead);
 69478        return BodyRead(destination, offset, count);
 479      } else {
 1480        internalReader = new ReadDataHandler(ReadingNotAvailable);
 1481        return 0;
 482      }
 483    }
 484
 485    /// <summary>
 486    /// Read a block of bytes from the stream.
 487    /// </summary>
 488    /// <param name="buffer">The destination for the bytes.</param>
 489    /// <param name="offset">The index to start storing data.</param>
 490    /// <param name="count">The number of bytes to attempt to read.</param>
 491    /// <returns>Returns the number of bytes read.</returns>
 492    /// <remarks>Zero bytes read means end of stream.</remarks>
 493    public override int Read(byte[] buffer, int offset, int count)
 494    {
 148495       if (buffer == null) {
 1496        throw new ArgumentNullException(nameof(buffer));
 497      }
 498
 147499       if (offset < 0) {
 1500        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");
 501      }
 502
 146503       if (count < 0) {
 1504        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");
 505      }
 506
 145507       if ((buffer.Length - offset) < count) {
 3508        throw new ArgumentException("Invalid offset/count combination");
 509      }
 510
 142511      return internalReader(buffer, offset, count);
 512    }
 513
 514    /// <summary>
 515    /// Reads a block of bytes from the current zip entry.
 516    /// </summary>
 517    /// <returns>
 518    /// The number of bytes read (this may be less than the length requested, even before the end of stream), or 0 on en
 519    /// </returns>
 520    /// <exception name="IOException">
 521    /// An i/o error occured.
 522    /// </exception>
 523    /// <exception cref="ZipException">
 524    /// The deflated stream is corrupted.
 525    /// </exception>
 526    /// <exception cref="InvalidOperationException">
 527    /// The stream is not open.
 528    /// </exception>
 529    int BodyRead(byte[] buffer, int offset, int count)
 530    {
 141531       if (crc == null) {
 0532        throw new InvalidOperationException("Closed");
 533      }
 534
 141535       if ((entry == null) || (count <= 0)) {
 46536        return 0;
 537      }
 538
 95539       if (offset + count > buffer.Length) {
 0540        throw new ArgumentException("Offset + count exceeds buffer size");
 541      }
 542
 95543      bool finished = false;
 544
 95545       switch (method) {
 546        case (int)CompressionMethod.Deflated:
 92547          count = base.Read(buffer, offset, count);
 92548           if (count <= 0) {
 16549             if (!inf.IsFinished) {
 0550              throw new ZipException("Inflater not finished!");
 551            }
 16552            inputBuffer.Available = inf.RemainingInput;
 553
 554            // A csize of -1 is from an unpatched local header
 16555             if ((flags & 8) == 0 &&
 16556              (inf.TotalIn != csize && csize != 0xFFFFFFFF && csize != -1 || inf.TotalOut != size)) {
 0557              throw new ZipException("Size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut
 558            }
 16559            inf.Reset();
 16560            finished = true;
 561          }
 16562          break;
 563
 564        case (int)CompressionMethod.Stored:
 3565           if ((count > csize) && (csize >= 0)) {
 0566            count = (int)csize;
 567          }
 568
 3569           if (count > 0) {
 3570            count = inputBuffer.ReadClearTextBuffer(buffer, offset, count);
 3571             if (count > 0) {
 3572              csize -= count;
 3573              size -= count;
 574            }
 575          }
 576
 3577           if (csize == 0) {
 2578            finished = true;
 2579          } else {
 1580             if (count < 0) {
 0581              throw new ZipException("EOF in stored block");
 582            }
 583          }
 584          break;
 585      }
 586
 95587       if (count > 0) {
 79588        crc.Update(buffer, offset, count);
 589      }
 590
 95591       if (finished) {
 18592        CompleteCloseEntry(true);
 593      }
 594
 95595      return count;
 596    }
 597
 598    /// <summary>
 599    /// Closes the zip input stream
 600    /// </summary>
 601    public override void Close()
 602    {
 61603      internalReader = new ReadDataHandler(ReadingNotAvailable);
 61604      crc = null;
 61605      entry = null;
 606
 61607      base.Close();
 61608    }
 609  }
 610}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipNameTransform.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipNameTransform.htm new file mode 100644 index 000000000..5f58e073a --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipNameTransform.htm @@ -0,0 +1,269 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipNameTransform - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipNameTransform
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipNameTransform.cs
Covered lines:66
Uncovered lines:11
Coverable lines:77
Total lines:220
Line coverage:85.7%
Branch coverage:67.6%
+

Metrics

+ + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor()1100100
.ctor(...)1100100
.cctor()1100100
TransformDirectory(...)385.7160
TransformFile(...)977.7870.59
MakeValidName(...)584.6288.89
IsValidName(...)485.7160
IsValidName(...)3100100
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipNameTransform.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Text;
 4using ICSharpCode.SharpZipLib.Core;
 5
 6namespace ICSharpCode.SharpZipLib.Zip
 7{
 8  /// <summary>
 9  /// ZipNameTransform transforms names as per the Zip file naming convention.
 10  /// </summary>
 11  /// <remarks>The use of absolute names is supported although its use is not valid
 12  /// according to Zip naming conventions, and should not be used if maximum compatability is desired.</remarks>
 13  public class ZipNameTransform : INameTransform
 14  {
 15    #region Constructors
 16    /// <summary>
 17    /// Initialize a new instance of <see cref="ZipNameTransform"></see>
 18    /// </summary>
 10119    public ZipNameTransform()
 20    {
 10121    }
 22
 23    /// <summary>
 24    /// Initialize a new instance of <see cref="ZipNameTransform"></see>
 25    /// </summary>
 26    /// <param name="trimPrefix">The string to trim from the front of paths if found.</param>
 527    public ZipNameTransform(string trimPrefix)
 28    {
 529      TrimPrefix = trimPrefix;
 530    }
 31    #endregion
 32
 33    /// <summary>
 34    /// Static constructor.
 35    /// </summary>
 36    static ZipNameTransform()
 37    {
 38      char[] invalidPathChars;
 139      invalidPathChars = Path.GetInvalidPathChars();
 140      int howMany = invalidPathChars.Length + 2;
 41
 142      InvalidEntryCharsRelaxed = new char[howMany];
 143      Array.Copy(invalidPathChars, 0, InvalidEntryCharsRelaxed, 0, invalidPathChars.Length);
 144      InvalidEntryCharsRelaxed[howMany - 1] = '*';
 145      InvalidEntryCharsRelaxed[howMany - 2] = '?';
 46
 147      howMany = invalidPathChars.Length + 4;
 148      InvalidEntryChars = new char[howMany];
 149      Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length);
 150      InvalidEntryChars[howMany - 1] = ':';
 151      InvalidEntryChars[howMany - 2] = '\\';
 152      InvalidEntryChars[howMany - 3] = '*';
 153      InvalidEntryChars[howMany - 4] = '?';
 154    }
 55
 56    /// <summary>
 57    /// Transform a windows directory name according to the Zip file naming conventions.
 58    /// </summary>
 59    /// <param name="name">The directory name to transform.</param>
 60    /// <returns>The transformed name.</returns>
 61    public string TransformDirectory(string name)
 62    {
 563      name = TransformFile(name);
 464       if (name.Length > 0) {
 465         if (!name.EndsWith("/", StringComparison.Ordinal)) {
 466          name += "/";
 67        }
 468      } else {
 069        throw new ZipException("Cannot have an empty directory name");
 70      }
 471      return name;
 72    }
 73
 74    /// <summary>
 75    /// Transform a windows file name according to the Zip file naming conventions.
 76    /// </summary>
 77    /// <param name="name">The file name to transform.</param>
 78    /// <returns>The transformed name.</returns>
 79    public string TransformFile(string name)
 80    {
 6592781       if (name != null) {
 6592782        string lowerName = name.ToLower();
 6592783         if ((trimPrefix_ != null) && (lowerName.IndexOf(trimPrefix_, StringComparison.Ordinal) == 0)) {
 784          name = name.Substring(trimPrefix_.Length);
 85        }
 86
 6592787        name = name.Replace(@"\", "/");
 6592788        name = WindowsPathUtils.DropPathRoot(name);
 89
 90        // Drop any leading slashes.
 6593291         while ((name.Length > 0) && (name[0] == '/')) {
 592          name = name.Remove(0, 1);
 93        }
 94
 95        // Drop any trailing slashes.
 6592796         while ((name.Length > 0) && (name[name.Length - 1] == '/')) {
 097          name = name.Remove(name.Length - 1, 1);
 98        }
 99
 100        // Convert consecutive // characters to /
 65927101        int index = name.IndexOf("//", StringComparison.Ordinal);
 65927102         while (index >= 0) {
 0103          name = name.Remove(index, 1);
 0104          index = name.IndexOf("//", StringComparison.Ordinal);
 105        }
 106
 65927107        name = MakeValidName(name, '_');
 65926108      } else {
 0109        name = string.Empty;
 110      }
 65926111      return name;
 112    }
 113
 114    /// <summary>
 115    /// Get/set the path prefix to be trimmed from paths if present.
 116    /// </summary>
 117    /// <remarks>The prefix is trimmed before any conversion from
 118    /// a windows path is done.</remarks>
 119    public string TrimPrefix {
 0120      get { return trimPrefix_; }
 121      set {
 5122        trimPrefix_ = value;
 5123         if (trimPrefix_ != null) {
 5124          trimPrefix_ = trimPrefix_.ToLower();
 125        }
 5126      }
 127    }
 128
 129    /// <summary>
 130    /// Force a name to be valid by replacing invalid characters with a fixed value
 131    /// </summary>
 132    /// <param name="name">The name to force valid</param>
 133    /// <param name="replacement">The replacement character to use.</param>
 134    /// <returns>Returns a valid name</returns>
 135    static string MakeValidName(string name, char replacement)
 136    {
 65927137      int index = name.IndexOfAny(InvalidEntryChars);
 65927138       if (index >= 0) {
 2139        var builder = new StringBuilder(name);
 140
 5141         while (index >= 0) {
 3142          builder[index] = replacement;
 143
 3144           if (index >= name.Length) {
 0145            index = -1;
 0146          } else {
 3147            index = name.IndexOfAny(InvalidEntryChars, index + 1);
 148          }
 149        }
 2150        name = builder.ToString();
 151      }
 152
 65927153       if (name.Length > 0xffff) {
 1154        throw new PathTooLongException();
 155      }
 156
 65926157      return name;
 158    }
 159
 160    /// <summary>
 161    /// Test a name to see if it is a valid name for a zip entry.
 162    /// </summary>
 163    /// <param name="name">The name to test.</param>
 164    /// <param name="relaxed">If true checking is relaxed about windows file names and absolute paths.</param>
 165    /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
 166    /// <remarks>Zip path names are actually in Unix format, and should only contain relative paths.
 167    /// This means that any path stored should not contain a drive or
 168    /// device letter, or a leading slash.  All slashes should forward slashes '/'.
 169    /// An empty name is valid for a file where the input comes from standard input.
 170    /// A null name is not considered valid.
 171    /// </remarks>
 172    public static bool IsValidName(string name, bool relaxed)
 173    {
 65916174      bool result = (name != null);
 175
 65916176       if (result) {
 65916177         if (relaxed) {
 65916178          result = name.IndexOfAny(InvalidEntryCharsRelaxed) < 0;
 65916179        } else {
 0180          result =
 0181            (name.IndexOfAny(InvalidEntryChars) < 0) &&
 0182            (name.IndexOf('/') != 0);
 183        }
 184      }
 185
 65916186      return result;
 187    }
 188
 189    /// <summary>
 190    /// Test a name to see if it is a valid name for a zip entry.
 191    /// </summary>
 192    /// <param name="name">The name to test.</param>
 193    /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
 194    /// <remarks>Zip path names are actually in unix format,
 195    /// and should only contain relative paths if a path is present.
 196    /// This means that the path stored should not contain a drive or
 197    /// device letter, or a leading slash.  All slashes should forward slashes '/'.
 198    /// An empty name is valid where the input comes from standard input.
 199    /// A null name is not considered valid.
 200    /// </remarks>
 201    public static bool IsValidName(string name)
 202    {
 2203      bool result =
 2204        (name != null) &&
 2205        (name.IndexOfAny(InvalidEntryChars) < 0) &&
 2206        (name.IndexOf('/') != 0)
 2207        ;
 1208      return result;
 209    }
 210
 211    #region Instance Fields
 212    string trimPrefix_;
 213    #endregion
 214
 215    #region Class Fields
 216    static readonly char[] InvalidEntryChars;
 217    static readonly char[] InvalidEntryCharsRelaxed;
 218    #endregion
 219  }
 220}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipOutputStream.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipOutputStream.htm new file mode 100644 index 000000000..92cd8d99a --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipOutputStream.htm @@ -0,0 +1,873 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipOutputStream - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipOutputStream
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipOutputStream.cs
Covered lines:285
Uncovered lines:48
Coverable lines:333
Total lines:816
Line coverage:85.5%
Branch coverage:78.4%
+

Metrics

+ + + + + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)100
SetComment(...)2100100
SetLevel(...)1100100
GetLevel()1100100
WriteLeShort(...)1100100
WriteLeInt(...)1100100
WriteLeLong(...)1100100
PutNextEntry(...)4088.7086.30
CloseEntry()1885.2577.14
WriteEncryptionHeader(...)1100100
AddExtraDataAES(...)100
WriteAESHeader(...)100
Write(...)97564.71
CopyAndEncrypt(...)410080
Finish()2690.4173.33
+

File(s)

+

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipOutputStream.cs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Collections;
 4using ICSharpCode.SharpZipLib.Checksum;
 5using ICSharpCode.SharpZipLib.Zip.Compression;
 6using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
 7
 8namespace ICSharpCode.SharpZipLib.Zip
 9{
 10  /// <summary>
 11  /// This is a DeflaterOutputStream that writes the files into a zip
 12  /// archive one after another.  It has a special method to start a new
 13  /// zip entry.  The zip entries contains information about the file name
 14  /// size, compressed size, CRC, etc.
 15  ///
 16  /// It includes support for Stored and Deflated entries.
 17  /// This class is not thread safe.
 18  /// <br/>
 19  /// <br/>Author of the original java version : Jochen Hoenicke
 20  /// </summary>
 21  /// <example> This sample shows how to create a zip file
 22  /// <code>
 23  /// using System;
 24  /// using System.IO;
 25  ///
 26  /// using ICSharpCode.SharpZipLib.Core;
 27  /// using ICSharpCode.SharpZipLib.Zip;
 28  ///
 29  /// class MainClass
 30  /// {
 31  ///   public static void Main(string[] args)
 32  ///   {
 33  ///     string[] filenames = Directory.GetFiles(args[0]);
 34  ///     byte[] buffer = new byte[4096];
 35  ///
 36  ///     using ( ZipOutputStream s = new ZipOutputStream(File.Create(args[1])) ) {
 37  ///
 38  ///       s.SetLevel(9); // 0 - store only to 9 - means best compression
 39  ///
 40  ///       foreach (string file in filenames) {
 41  ///         ZipEntry entry = new ZipEntry(file);
 42  ///         s.PutNextEntry(entry);
 43  ///
 44  ///         using (FileStream fs = File.OpenRead(file)) {
 45  ///            StreamUtils.Copy(fs, s, buffer);
 46  ///         }
 47  ///       }
 48  ///     }
 49  ///   }
 50  /// }
 51  /// </code>
 52  /// </example>
 53  public class ZipOutputStream : DeflaterOutputStream
 54  {
 55    #region Constructors
 56    /// <summary>
 57    /// Creates a new Zip output stream, writing a zip archive.
 58    /// </summary>
 59    /// <param name="baseOutputStream">
 60    /// The output stream to which the archive contents are written.
 61    /// </param>
 62    public ZipOutputStream(Stream baseOutputStream)
 8763      : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true))
 64    {
 8765    }
 66
 67    /// <summary>
 68    /// Creates a new Zip output stream, writing a zip archive.
 69    /// </summary>
 70    /// <param name="baseOutputStream">The output stream to which the archive contents are written.</param>
 71    /// <param name="bufferSize">Size of the buffer to use.</param>
 72    public ZipOutputStream(Stream baseOutputStream, int bufferSize)
 073      : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true), bufferSize)
 74    {
 075    }
 76    #endregion
 77
 78    /// <summary>
 79    /// Gets a flag value of true if the central header has been added for this archive; false if it has not been added.
 80    /// </summary>
 81    /// <remarks>No further entries can be added once this has been done.</remarks>
 82    public bool IsFinished {
 83      get {
 184        return entries == null;
 85      }
 86    }
 87
 88    /// <summary>
 89    /// Set the zip file comment.
 90    /// </summary>
 91    /// <param name="comment">
 92    /// The comment text for the entire archive.
 93    /// </param>
 94    /// <exception name ="ArgumentOutOfRangeException">
 95    /// The converted comment is longer than 0xffff bytes.
 96    /// </exception>
 97    public void SetComment(string comment)
 98    {
 99      // TODO: Its not yet clear how to handle unicode comments here.
 8100      byte[] commentBytes = ZipConstants.ConvertToArray(comment);
 8101       if (commentBytes.Length > 0xffff) {
 1102        throw new ArgumentOutOfRangeException(nameof(comment));
 103      }
 7104      zipComment = commentBytes;
 7105    }
 106
 107    /// <summary>
 108    /// Sets the compression level.  The new level will be activated
 109    /// immediately.
 110    /// </summary>
 111    /// <param name="level">The new compression level (1 to 9).</param>
 112    /// <exception cref="ArgumentOutOfRangeException">
 113    /// Level specified is not supported.
 114    /// </exception>
 115    /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Deflater"/>
 116    public void SetLevel(int level)
 117    {
 55118      deflater_.SetLevel(level);
 55119      defaultCompressionLevel = level;
 55120    }
 121
 122    /// <summary>
 123    /// Get the current deflater compression level
 124    /// </summary>
 125    /// <returns>The current compression level</returns>
 126    public int GetLevel()
 127    {
 3128      return deflater_.GetLevel();
 129    }
 130
 131    /// <summary>
 132    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
 133    /// </summary>
 134    /// <remarks>Older archivers may not understand Zip64 extensions.
 135    /// If backwards compatability is an issue be careful when adding <see cref="ZipEntry.Size">entries</see> to an arch
 136    /// Setting this property to off is workable but less desirable as in those circumstances adding a file
 137    /// larger then 4GB will fail.</remarks>
 138    public UseZip64 UseZip64 {
 0139      get { return useZip64_; }
 14140      set { useZip64_ = value; }
 141    }
 142
 143    /// <summary>
 144    /// Write an unsigned short in little endian byte order.
 145    /// </summary>
 146    private void WriteLeShort(int value)
 147    {
 148      unchecked {
 6369149        baseOutputStream_.WriteByte((byte)(value & 0xff));
 6369150        baseOutputStream_.WriteByte((byte)((value >> 8) & 0xff));
 151      }
 6369152    }
 153
 154    /// <summary>
 155    /// Write an int in little endian byte order.
 156    /// </summary>
 157    private void WriteLeInt(int value)
 158    {
 159      unchecked {
 2286160        WriteLeShort(value);
 2286161        WriteLeShort(value >> 16);
 162      }
 2286163    }
 164
 165    /// <summary>
 166    /// Write an int in little endian byte order.
 167    /// </summary>
 168    private void WriteLeLong(long value)
 169    {
 170      unchecked {
 268171        WriteLeInt((int)value);
 268172        WriteLeInt((int)(value >> 32));
 173      }
 268174    }
 175
 176    /// <summary>
 177    /// Starts a new Zip entry. It automatically closes the previous
 178    /// entry if present.
 179    /// All entry elements bar name are optional, but must be correct if present.
 180    /// If the compression method is stored and the output is not patchable
 181    /// the compression for that entry is automatically changed to deflate level 0
 182    /// </summary>
 183    /// <param name="entry">
 184    /// the entry.
 185    /// </param>
 186    /// <exception cref="System.ArgumentNullException">
 187    /// if entry passed is null.
 188    /// </exception>
 189    /// <exception cref="System.IO.IOException">
 190    /// if an I/O error occured.
 191    /// </exception>
 192    /// <exception cref="System.InvalidOperationException">
 193    /// if stream was finished
 194    /// </exception>
 195    /// <exception cref="ZipException">
 196    /// Too many entries in the Zip file<br/>
 197    /// Entry name is too long<br/>
 198    /// Finish has already been called<br/>
 199    /// </exception>
 200    public void PutNextEntry(ZipEntry entry)
 201    {
 130202       if (entry == null) {
 0203        throw new ArgumentNullException(nameof(entry));
 204      }
 205
 130206       if (entries == null) {
 1207        throw new InvalidOperationException("ZipOutputStream was finished");
 208      }
 209
 129210       if (curEntry != null) {
 48211        CloseEntry();
 212      }
 213
 129214       if (entries.Count == int.MaxValue) {
 0215        throw new ZipException("Too many entries for Zip file");
 216      }
 217
 129218      CompressionMethod method = entry.CompressionMethod;
 129219      int compressionLevel = defaultCompressionLevel;
 220
 221      // Clear flags that the library manages internally
 129222      entry.Flags &= (int)GeneralBitFlags.UnicodeText;
 129223      patchEntryHeader = false;
 224
 225      bool headerInfoAvailable;
 226
 227      // No need to compress - definitely no data.
 129228       if (entry.Size == 0) {
 1229        entry.CompressedSize = entry.Size;
 1230        entry.Crc = 0;
 1231        method = CompressionMethod.Stored;
 1232        headerInfoAvailable = true;
 1233      } else {
 128234        headerInfoAvailable = (entry.Size >= 0) && entry.HasCrc && entry.CompressedSize >= 0;
 235
 236        // Switch to deflation if storing isnt possible.
 128237         if (method == CompressionMethod.Stored) {
 13238           if (!headerInfoAvailable) {
 13239             if (!CanPatchEntries) {
 240              // Can't patch entries so storing is not possible.
 5241              method = CompressionMethod.Deflated;
 5242              compressionLevel = 0;
 243            }
 5244          } else // entry.size must be > 0
 245            {
 0246            entry.CompressedSize = entry.Size;
 0247            headerInfoAvailable = entry.HasCrc;
 248          }
 249        }
 250      }
 251
 129252       if (headerInfoAvailable == false) {
 128253         if (CanPatchEntries == false) {
 254          // Only way to record size and compressed size is to append a data descriptor
 255          // after compressed data.
 256
 257          // Stored entries of this form have already been converted to deflating.
 32258          entry.Flags |= 8;
 32259        } else {
 96260          patchEntryHeader = true;
 261        }
 262      }
 263
 129264       if (Password != null) {
 33265        entry.IsCrypted = true;
 33266         if (entry.Crc < 0) {
 267          // Need to append a data descriptor as the crc isnt available for use
 268          // with encryption, the date is used instead.  Setting the flag
 269          // indicates this to the decompressor.
 29270          entry.Flags |= 8;
 271        }
 272      }
 273
 129274      entry.Offset = offset;
 129275      entry.CompressionMethod = (CompressionMethod)method;
 276
 129277      curMethod = method;
 129278      sizePatchPos = -1;
 279
 129280       if ((useZip64_ == UseZip64.On) || ((entry.Size < 0) && (useZip64_ == UseZip64.Dynamic))) {
 121281        entry.ForceZip64();
 282      }
 283
 284      // Write the local file header
 129285      WriteLeInt(ZipConstants.LocalHeaderSignature);
 286
 129287      WriteLeShort(entry.Version);
 129288      WriteLeShort(entry.Flags);
 129289      WriteLeShort((byte)entry.CompressionMethodForHeader);
 129290      WriteLeInt((int)entry.DosTime);
 291
 292      // TODO: Refactor header writing.  Its done in several places.
 129293       if (headerInfoAvailable) {
 1294        WriteLeInt((int)entry.Crc);
 1295         if (entry.LocalHeaderRequiresZip64) {
 1296          WriteLeInt(-1);
 1297          WriteLeInt(-1);
 1298        } else {
 0299          WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.Compressed
 0300          WriteLeInt((int)entry.Size);
 301        }
 0302      } else {
 128303         if (patchEntryHeader) {
 96304          crcPatchPos = baseOutputStream_.Position;
 305        }
 128306        WriteLeInt(0);  // Crc
 307
 128308         if (patchEntryHeader) {
 96309          sizePatchPos = baseOutputStream_.Position;
 310        }
 311
 312        // For local header both sizes appear in Zip64 Extended Information
 128313         if (entry.LocalHeaderRequiresZip64 || patchEntryHeader) {
 125314          WriteLeInt(-1);
 125315          WriteLeInt(-1);
 125316        } else {
 3317          WriteLeInt(0);  // Compressed size
 3318          WriteLeInt(0);  // Uncompressed size
 319        }
 320      }
 321
 129322      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 323
 129324       if (name.Length > 0xFFFF) {
 0325        throw new ZipException("Entry name too long.");
 326      }
 327
 129328      var ed = new ZipExtraData(entry.ExtraData);
 329
 129330       if (entry.LocalHeaderRequiresZip64) {
 122331        ed.StartNewEntry();
 122332         if (headerInfoAvailable) {
 1333          ed.AddLeLong(entry.Size);
 1334          ed.AddLeLong(entry.CompressedSize);
 1335        } else {
 121336          ed.AddLeLong(-1);
 121337          ed.AddLeLong(-1);
 338        }
 122339        ed.AddNewEntry(1);
 340
 122341         if (!ed.Find(1)) {
 0342          throw new ZipException("Internal error cant find extra data");
 343        }
 344
 122345         if (patchEntryHeader) {
 92346          sizePatchPos = ed.CurrentReadIndex;
 347        }
 92348      } else {
 7349        ed.Delete(1);
 350      }
 351
 129352       if (entry.AESKeySize > 0) {
 0353        AddExtraDataAES(entry, ed);
 354      }
 129355      byte[] extra = ed.GetEntryData();
 356
 129357      WriteLeShort(name.Length);
 129358      WriteLeShort(extra.Length);
 359
 129360       if (name.Length > 0) {
 129361        baseOutputStream_.Write(name, 0, name.Length);
 362      }
 363
 128364       if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {
 91365        sizePatchPos += baseOutputStream_.Position;
 366      }
 367
 128368       if (extra.Length > 0) {
 121369        baseOutputStream_.Write(extra, 0, extra.Length);
 370      }
 371
 128372      offset += ZipConstants.LocalHeaderBaseSize + name.Length + extra.Length;
 373      // Fix offsetOfCentraldir for AES
 128374       if (entry.AESKeySize > 0)
 0375        offset += entry.AESOverheadSize;
 376
 377      // Activate the entry.
 128378      curEntry = entry;
 128379      crc.Reset();
 128380       if (method == CompressionMethod.Deflated) {
 119381        deflater_.Reset();
 119382        deflater_.SetLevel(compressionLevel);
 383      }
 128384      size = 0;
 385
 128386       if (entry.IsCrypted) {
 33387         if (entry.AESKeySize > 0) {
 0388          WriteAESHeader(entry);
 0389        } else {
 33390           if (entry.Crc < 0) {            // so testing Zip will says its ok
 29391            WriteEncryptionHeader(entry.DosTime << 16);
 29392          } else {
 4393            WriteEncryptionHeader(entry.Crc);
 394          }
 395        }
 396      }
 99397    }
 398
 399    /// <summary>
 400    /// Closes the current entry, updating header and footer information as required
 401    /// </summary>
 402    /// <exception cref="System.IO.IOException">
 403    /// An I/O error occurs.
 404    /// </exception>
 405    /// <exception cref="System.InvalidOperationException">
 406    /// No entry is active.
 407    /// </exception>
 408    public void CloseEntry()
 409    {
 128410       if (curEntry == null) {
 0411        throw new InvalidOperationException("No open entry");
 412      }
 413
 128414      long csize = size;
 415
 416      // First finish the deflater, if appropriate
 128417       if (curMethod == CompressionMethod.Deflated) {
 119418         if (size >= 0) {
 119419          base.Finish();
 119420          csize = deflater_.TotalOut;
 119421        } else {
 0422          deflater_.Reset();
 423        }
 424      }
 425
 426      // Write the AES Authentication Code (a hash of the compressed and encrypted data)
 128427       if (curEntry.AESKeySize > 0) {
 0428        baseOutputStream_.Write(AESAuthCode, 0, 10);
 429      }
 430
 128431       if (curEntry.Size < 0) {
 121432        curEntry.Size = size;
 128433       } else if (curEntry.Size != size) {
 0434        throw new ZipException("size was " + size + ", but I expected " + curEntry.Size);
 435      }
 436
 128437       if (curEntry.CompressedSize < 0) {
 127438        curEntry.CompressedSize = csize;
 128439       } else if (curEntry.CompressedSize != csize) {
 0440        throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize);
 441      }
 442
 128443       if (curEntry.Crc < 0) {
 114444        curEntry.Crc = crc.Value;
 128445       } else if (curEntry.Crc != crc.Value) {
 0446        throw new ZipException("crc was " + crc.Value + ", but I expected " + curEntry.Crc);
 447      }
 448
 128449      offset += csize;
 450
 128451       if (curEntry.IsCrypted) {
 33452         if (curEntry.AESKeySize > 0) {
 0453          curEntry.CompressedSize += curEntry.AESOverheadSize;
 454
 0455        } else {
 33456          curEntry.CompressedSize += ZipConstants.CryptoHeaderSize;
 457        }
 458      }
 459
 460      // Patch the header if possible
 128461       if (patchEntryHeader) {
 95462        patchEntryHeader = false;
 463
 95464        long curPos = baseOutputStream_.Position;
 95465        baseOutputStream_.Seek(crcPatchPos, SeekOrigin.Begin);
 95466        WriteLeInt((int)curEntry.Crc);
 467
 95468         if (curEntry.LocalHeaderRequiresZip64) {
 469
 91470           if (sizePatchPos == -1) {
 0471            throw new ZipException("Entry requires zip64 but this has been turned off");
 472          }
 473
 91474          baseOutputStream_.Seek(sizePatchPos, SeekOrigin.Begin);
 91475          WriteLeLong(curEntry.Size);
 91476          WriteLeLong(curEntry.CompressedSize);
 91477        } else {
 4478          WriteLeInt((int)curEntry.CompressedSize);
 4479          WriteLeInt((int)curEntry.Size);
 480        }
 95481        baseOutputStream_.Seek(curPos, SeekOrigin.Begin);
 482      }
 483
 484      // Add data descriptor if flagged as required
 128485       if ((curEntry.Flags & 8) != 0) {
 48486        WriteLeInt(ZipConstants.DataDescriptorSignature);
 48487        WriteLeInt(unchecked((int)curEntry.Crc));
 488
 48489         if (curEntry.LocalHeaderRequiresZip64) {
 43490          WriteLeLong(curEntry.CompressedSize);
 43491          WriteLeLong(curEntry.Size);
 43492          offset += ZipConstants.Zip64DataDescriptorSize;
 43493        } else {
 5494          WriteLeInt((int)curEntry.CompressedSize);
 5495          WriteLeInt((int)curEntry.Size);
 5496          offset += ZipConstants.DataDescriptorSize;
 497        }
 498      }
 499
 128500      entries.Add(curEntry);
 128501      curEntry = null;
 128502    }
 503
 504    void WriteEncryptionHeader(long crcValue)
 505    {
 33506      offset += ZipConstants.CryptoHeaderSize;
 507
 33508      InitializePassword(Password);
 509
 33510      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
 33511      var rnd = new Random();
 33512      rnd.NextBytes(cryptBuffer);
 33513      cryptBuffer[11] = (byte)(crcValue >> 24);
 514
 33515      EncryptBlock(cryptBuffer, 0, cryptBuffer.Length);
 33516      baseOutputStream_.Write(cryptBuffer, 0, cryptBuffer.Length);
 33517    }
 518
 519    private static void AddExtraDataAES(ZipEntry entry, ZipExtraData extraData)
 520    {
 521
 522      // Vendor Version: AE-1 IS 1. AE-2 is 2. With AE-2 no CRC is required and 0 is stored.
 523      const int VENDOR_VERSION = 2;
 524      // Vendor ID is the two ASCII characters "AE".
 525      const int VENDOR_ID = 0x4541; //not 6965;
 0526      extraData.StartNewEntry();
 527      // Pack AES extra data field see http://www.winzip.com/aes_info.htm
 528      //extraData.AddLeShort(7);              // Data size (currently 7)
 0529      extraData.AddLeShort(VENDOR_VERSION);               // 2 = AE-2
 0530      extraData.AddLeShort(VENDOR_ID);                    // "AE"
 0531      extraData.AddData(entry.AESEncryptionStrength);     //  1 = 128, 2 = 192, 3 = 256
 0532      extraData.AddLeShort((int)entry.CompressionMethod); // The actual compression method used to compress the file
 0533      extraData.AddNewEntry(0x9901);
 0534    }
 535
 536    // Replaces WriteEncryptionHeader for AES
 537    //
 538    private void WriteAESHeader(ZipEntry entry)
 539    {
 540      byte[] salt;
 541      byte[] pwdVerifier;
 0542      InitializeAESPassword(entry, Password, out salt, out pwdVerifier);
 543      // File format for AES:
 544      // Size (bytes)   Content
 545      // ------------   -------
 546      // Variable       Salt value
 547      // 2              Password verification value
 548      // Variable       Encrypted file data
 549      // 10             Authentication code
 550      //
 551      // Value in the "compressed size" fields of the local file header and the central directory entry
 552      // is the total size of all the items listed above. In other words, it is the total size of the
 553      // salt value, password verification value, encrypted data, and authentication code.
 0554      baseOutputStream_.Write(salt, 0, salt.Length);
 0555      baseOutputStream_.Write(pwdVerifier, 0, pwdVerifier.Length);
 0556    }
 557
 558    /// <summary>
 559    /// Writes the given buffer to the current entry.
 560    /// </summary>
 561    /// <param name="buffer">The buffer containing data to write.</param>
 562    /// <param name="offset">The offset of the first byte to write.</param>
 563    /// <param name="count">The number of bytes to write.</param>
 564    /// <exception cref="ZipException">Archive size is invalid</exception>
 565    /// <exception cref="System.InvalidOperationException">No entry is active.</exception>
 566    public override void Write(byte[] buffer, int offset, int count)
 567    {
 4503568       if (curEntry == null) {
 0569        throw new InvalidOperationException("No open entry.");
 570      }
 571
 4503572       if (buffer == null) {
 0573        throw new ArgumentNullException(nameof(buffer));
 574      }
 575
 4503576       if (offset < 0) {
 0577        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");
 578      }
 579
 4503580       if (count < 0) {
 0581        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");
 582      }
 583
 4503584       if ((buffer.Length - offset) < count) {
 0585        throw new ArgumentException("Invalid offset/count combination");
 586      }
 587
 4503588      crc.Update(buffer, offset, count);
 4502589      size += count;
 590
 4502591       switch (curMethod) {
 592        case CompressionMethod.Deflated:
 4303593          base.Write(buffer, offset, count);
 4303594          break;
 595
 596        case CompressionMethod.Stored:
 199597           if (Password != null) {
 99598            CopyAndEncrypt(buffer, offset, count);
 99599          } else {
 100600            baseOutputStream_.Write(buffer, offset, count);
 601          }
 602          break;
 603      }
 100604    }
 605
 606    void CopyAndEncrypt(byte[] buffer, int offset, int count)
 607    {
 608      const int CopyBufferSize = 4096;
 99609      byte[] localBuffer = new byte[CopyBufferSize];
 198610       while (count > 0) {
 99611         int bufferCount = (count < CopyBufferSize) ? count : CopyBufferSize;
 612
 99613        Array.Copy(buffer, offset, localBuffer, 0, bufferCount);
 99614        EncryptBlock(localBuffer, 0, bufferCount);
 99615        baseOutputStream_.Write(localBuffer, 0, bufferCount);
 99616        count -= bufferCount;
 99617        offset += bufferCount;
 618      }
 99619    }
 620
 621    /// <summary>
 622    /// Finishes the stream.  This will write the central directory at the
 623    /// end of the zip file and flush the stream.
 624    /// </summary>
 625    /// <remarks>
 626    /// This is automatically called when the stream is closed.
 627    /// </remarks>
 628    /// <exception cref="System.IO.IOException">
 629    /// An I/O error occurs.
 630    /// </exception>
 631    /// <exception cref="ZipException">
 632    /// Comment exceeds the maximum length<br/>
 633    /// Entry name exceeds the maximum length
 634    /// </exception>
 635    public override void Finish()
 636    {
 88637       if (entries == null) {
 2638        return;
 639      }
 640
 86641       if (curEntry != null) {
 77642        CloseEntry();
 643      }
 644
 86645      long numEntries = entries.Count;
 86646      long sizeEntries = 0;
 647
 428648      foreach (ZipEntry entry in entries) {
 128649        WriteLeInt(ZipConstants.CentralHeaderSignature);
 128650        WriteLeShort(ZipConstants.VersionMadeBy);
 128651        WriteLeShort(entry.Version);
 128652        WriteLeShort(entry.Flags);
 128653        WriteLeShort((short)entry.CompressionMethodForHeader);
 128654        WriteLeInt((int)entry.DosTime);
 128655        WriteLeInt((int)entry.Crc);
 656
 128657         if (entry.IsZip64Forced() ||
 128658          (entry.CompressedSize >= uint.MaxValue)) {
 121659          WriteLeInt(-1);
 121660        } else {
 7661          WriteLeInt((int)entry.CompressedSize);
 662        }
 663
 128664         if (entry.IsZip64Forced() ||
 128665          (entry.Size >= uint.MaxValue)) {
 121666          WriteLeInt(-1);
 121667        } else {
 7668          WriteLeInt((int)entry.Size);
 669        }
 670
 128671        byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 672
 128673         if (name.Length > 0xffff) {
 0674          throw new ZipException("Name too long.");
 675        }
 676
 128677        var ed = new ZipExtraData(entry.ExtraData);
 678
 128679         if (entry.CentralHeaderRequiresZip64) {
 121680          ed.StartNewEntry();
 121681           if (entry.IsZip64Forced() ||
 121682            (entry.Size >= 0xffffffff)) {
 121683            ed.AddLeLong(entry.Size);
 684          }
 685
 121686           if (entry.IsZip64Forced() ||
 121687            (entry.CompressedSize >= 0xffffffff)) {
 121688            ed.AddLeLong(entry.CompressedSize);
 689          }
 690
 121691           if (entry.Offset >= 0xffffffff) {
 0692            ed.AddLeLong(entry.Offset);
 693          }
 694
 121695          ed.AddNewEntry(1);
 121696        } else {
 7697          ed.Delete(1);
 698        }
 699
 128700         if (entry.AESKeySize > 0) {
 0701          AddExtraDataAES(entry, ed);
 702        }
 128703        byte[] extra = ed.GetEntryData();
 704
 128705         byte[] entryComment =
 128706          (entry.Comment != null) ?
 128707          ZipConstants.ConvertToArray(entry.Flags, entry.Comment) :
 128708          new byte[0];
 709
 128710         if (entryComment.Length > 0xffff) {
 0711          throw new ZipException("Comment too long.");
 712        }
 713
 128714        WriteLeShort(name.Length);
 128715        WriteLeShort(extra.Length);
 128716        WriteLeShort(entryComment.Length);
 128717        WriteLeShort(0);    // disk number
 128718        WriteLeShort(0);    // internal file attributes
 719                  // external file attributes
 720
 128721         if (entry.ExternalFileAttributes != -1) {
 4722          WriteLeInt(entry.ExternalFileAttributes);
 4723        } else {
 124724           if (entry.IsDirectory) {                         // mark entry as directory (from nikolam.AT.perfectinfo.com)
 8725            WriteLeInt(16);
 8726          } else {
 116727            WriteLeInt(0);
 728          }
 729        }
 730
 128731         if (entry.Offset >= uint.MaxValue) {
 0732          WriteLeInt(-1);
 0733        } else {
 128734          WriteLeInt((int)entry.Offset);
 735        }
 736
 128737         if (name.Length > 0) {
 128738          baseOutputStream_.Write(name, 0, name.Length);
 739        }
 740
 128741         if (extra.Length > 0) {
 121742          baseOutputStream_.Write(extra, 0, extra.Length);
 743        }
 744
 128745         if (entryComment.Length > 0) {
 0746          baseOutputStream_.Write(entryComment, 0, entryComment.Length);
 747        }
 748
 128749        sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length;
 750      }
 751
 86752      using (ZipHelperStream zhs = new ZipHelperStream(baseOutputStream_)) {
 86753        zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment);
 85754      }
 755
 85756      entries = null;
 85757    }
 758
 759    #region Instance Fields
 760    /// <summary>
 761    /// The entries for the archive.
 762    /// </summary>
 87763    ArrayList entries = new ArrayList();
 764
 765    /// <summary>
 766    /// Used to track the crc of data added to entries.
 767    /// </summary>
 87768    Crc32 crc = new Crc32();
 769
 770    /// <summary>
 771    /// The current entry being added.
 772    /// </summary>
 773    ZipEntry curEntry;
 774
 87775    int defaultCompressionLevel = Deflater.DEFAULT_COMPRESSION;
 776
 87777    CompressionMethod curMethod = CompressionMethod.Deflated;
 778
 779    /// <summary>
 780    /// Used to track the size of data for an entry during writing.
 781    /// </summary>
 782    long size;
 783
 784    /// <summary>
 785    /// Offset to be recorded for each entry in the central header.
 786    /// </summary>
 787    long offset;
 788
 789    /// <summary>
 790    /// Comment for the entire archive recorded in central header.
 791    /// </summary>
 87792    byte[] zipComment = new byte[0];
 793
 794    /// <summary>
 795    /// Flag indicating that header patching is required for the current entry.
 796    /// </summary>
 797    bool patchEntryHeader;
 798
 799    /// <summary>
 800    /// Position to patch crc
 801    /// </summary>
 87802    long crcPatchPos = -1;
 803
 804    /// <summary>
 805    /// Position to patch size.
 806    /// </summary>
 87807    long sizePatchPos = -1;
 808
 809    // Default is dynamic which is not backwards compatible and can cause problems
 810    // with XP's built in compression which cant read Zip64 archives.
 811    // However it does avoid the situation were a large file is added and cannot be completed correctly.
 812    // NOTE: Setting the size for entries before they are added is the best solution!
 87813    UseZip64 useZip64_ = UseZip64.Dynamic;
 814    #endregion
 815  }
 816}
+
+ + \ No newline at end of file diff --git a/docs/opencover/ICSharpCode.SharpZipLib_ZipTestResultHandler.htm b/docs/opencover/ICSharpCode.SharpZipLib_ZipTestResultHandler.htm new file mode 100644 index 000000000..3528bdd56 --- /dev/null +++ b/docs/opencover/ICSharpCode.SharpZipLib_ZipTestResultHandler.htm @@ -0,0 +1,29 @@ + + + + +ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler - Coverage Report + +
+

Summary

+ ++++ + + + + + + + + + + +
Class:ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler
Assembly:ICSharpCode.SharpZipLib
File(s):
Covered lines:0
Uncovered lines:0
Coverable lines:0
Total lines:0
Line coverage:
+

File(s)

+

No files found. This usually happens if a file isn't covered by a test or the class does not contain any sequence points (e.g. a class that only contains auto properties).

+
+ + \ No newline at end of file diff --git a/docs/opencover/combined.js b/docs/opencover/combined.js new file mode 100644 index 000000000..e57ae7692 --- /dev/null +++ b/docs/opencover/combined.js @@ -0,0 +1,1302 @@ +/*! jQuery v1.11.2 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.2",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1; +return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("